|Bruce Eckel’s Thinking in Java||Contents | Prev | Next|
appendix contains suggestions to help guide you while performing low-level
program design, and also while writing code.
the first letter of class names. The first letter of fields, methods, and
objects (handles) should be lowercase. All identifiers should run their words
together, and capitalize the first letter of all intermediate words. For example:
the letters of
primitive identifiers that have constant initializers in their definitions.
This indicates they are compile-time constants.
are a special case: they are all lowercase letters, even for intermediate
words. The domain extension (com, org, net, edu, etc.) should also be
lowercase. (This was a change between Java 1.1
and Java 1.2.)
creating a class for general-purpose use, follow a “canonical form”
and include definitions for
each class you create, consider including a
that contains code to test that class. You don’t need to remove the test
code to use the class in a project, and if you make any changes you can easily
re-run the tests. This code also provides examples of how to use your class.
should be kept to brief, functional units that describe and implement a
discrete part of a class interface. Ideally, methods should be concise; if they
are long you might want to search for a way to break them up into several
shorter methods. This will also foster reuse within your class. (Sometimes
methods must be large, but they should still do just one thing.)
you design a class, think about the client programmer’s perspective (the
class should be fairly obvious to use) and the perspective of the person
maintaining the code (anticipate the kind of changes that will be made, to make
to keep classes small and focused. Clues to suggest redesign of a class are:
A complicated switch statement: consider using polymorphism
A large number of methods that cover broadly different types of operations:
consider using several classes
A large number of member variables that concern broadly different
characteristics: consider using several classes
things as “
as possible.” Once you publicize an aspect of your library (a method, a
class, a field), you can never take it out. If you do, you’ll wreck
somebody’s existing code, forcing them to rewrite and redesign. If you
publicize only what you must, you can change everything else with impunity, and
since designs tend to evolve this is an important freedom. Privacy is
especially important when dealing with multithreading – only
fields can be protected against un-
out for “giant object syndrome.” This is often an affliction of
procedural programmers who are new to OOP and who end up writing a procedural
program and sticking it inside one or two giant objects. With the exception of
application frameworks, objects represent concepts in your application, not the
you must do something ugly, at least localize the ugliness inside a class.
you notice classes that appear to have high coupling with each other, consider
the coding and maintenance improvements you might get by using inner classes
the code with an inner class
comments liberally, and use the
syntax to produce your program documentation.
using “magic numbers,” which are numbers hard-wired into code.
These are a nightmare if you need to change them, since you never know if
“100” means “the array size” or “something else
entirely.” Instead, create a constant with a descriptive name and use the
constant identifier throughout your program. This makes the program easier to
understand and much easier to maintain.
terms of constructors and exceptions, you’ll generally want to re-throw
any exceptions that you catch while in a constructor if it causes failure of
the creation of that object, so the caller doesn’t continue blindly,
thinking that the object was created correctly.
your class requires any cleanup when the client programmer is finished with the
object, place the cleanup code in a single, well- defined method with a name
that clearly suggests its purpose. In addition, place a
flag in the class to indicate whether the object has been cleaned up. In the
method for the class, check to make sure that the object has been cleaned up
and throw a class derived from
if it hasn’t, to indicate a programming error. Before relying on such a
scheme, ensure that
on your system. (You might need to call
to ensure this behavior.)
an object must be cleaned up (other than by garbage collection) within a
particular scope, use the following approach: Initialize the object and, if
successful, immediately enter a
block with a
clause that performs the cleanup.
during inheritance, remember to call
(this is not necessary if
is your immediate superclass). You should call
act of your overridden
rather than the first, to ensure that base-class components are still valid if
you need them.
you are creating a fixed-size collection of objects, transfer them to an array
(especially if you’re returning this collection from a method). This way
you get the benefit of the array’s compile-time type checking, and the
recipient of the array might not need to cast the objects in the array in order
to use them.
classes. If you know something is going to be a base class, your first choice
should be to make it an
and only if you’re forced to have method definitions or member variables
should you change it to an
about what the client wants to do, while a class tends to focus on (or allow)
constructors, do only what is necessary to set the object into the proper
state. Actively avoid calling other methods (except for
methods) since those methods can be overridden by someone else to produce
unexpected results during construction. (See Chapter 7 for details.)
should not simply hold some data; they should also have well-defined behaviors.
composition first when creating new classes from existing classes. You should
only used inheritance if it is required by your design. If you use inheritance
where composition will work, your designs will become needlessly complicated.
inheritance and method overriding to express differences in behavior, and
fields to express variations in state. An extreme example of what not to do is
inheriting different classes to represent colors instead of using a
avoid a highly frustrating experience, make sure that there’s only one
class of each name anywhere in your classpath. Otherwise, the compiler can find
the identically-named other class first, and report error messages that make no
sense. If you suspect that you are having a classpath problem, try looking for
files with the same names at each of the starting points in your classpath.
using the event “adapters” in the Java 1.1
AWT, there’s a particularly easy pitfall you can encounter. If you
override one of the adapter methods and you don’t quite get the spelling
right, you’ll end up adding a new method rather than overriding an
existing method. However, this is perfectly legal, so you won’t get any
error message from the compiler or run-time system – your code simply
won’t work correctly.
design patterns to eliminate “naked functionality.” That is, if
only one object of your class should be created, don’t bolt ahead to the
application and write a comment “Make only one of these.” Wrap it
in a singleton. If you have a lot of messy code in your main program that
creates your objects, look for a creational pattern like a factory method in
which you can encapsulate that creation. Eliminating “naked
functionality” will not only make your code much easier to understand and
maintain, it will also make it more bulletproof against the well-intentioned
maintainers that come after you.
out for “analysis paralysis.” Remember that you must usually move
forward in a project before you know everything, and that often the best and
fastest way to learn about some of your unknown factors is to go to the next
step rather than trying to figure it out in your head.
out for premature optimization. First make it work, then make it fast –
but only if you must, and only if it’s proven that there is a performance
bottleneck in a particular section of your code. Unless you have used a
profiler to discover a bottleneck, you will probably be wasting your time. The
hidden cost of performance tweaks is that your code becomes less understandable
that code is read much more than it is written. Clean designs make for
easy-to-understand programs, but comments, detailed explanations, and examples
are invaluable. They will help both you and everyone who comes after you. If
nothing else, the frustration of trying to ferret out useful information from
the online Java documentation should convince you.
you think you’ve got a good analysis, design, or implementation, do a
walkthrough. Bring someone in from outside your group – this
doesn’t have to be a consultant, but can be someone from another group
within your company. Reviewing your work with a pair of fresh eyes can reveal
problems at a stage where it’s much easier to fix them and more than pays
for the time and money “lost” to the walkthrough process.
always pays off. In the short term it might seem like it takes much longer to
come up with a truly graceful solution to a problem, but when it works the
first time and easily adapts to new situations instead of requiring hours,
days, or months of struggle, you’ll see the rewards (even if no one can
measure them). And there’s nothing that matches the feeling that comes
from knowing you’ve got an amazing design. Resist the urge to hurry; it
will only slow you down.
can find other programming guidelines on the Web. A good set of links can be