The interface gives us additional punch in two ways. We maintain consistency
across our implementations of common ideas, and we enforce the interfaces so
that we can reuse our designs. Few novice programmers appreciate the power
or simplicity of interfaces.
Consider the Cloneable interface
If our object might need to be cloned, then we should implement the Clone-
able interface. This interface is used by several design patterns. We should
often take the safer road by implementing from scratch rather than picking up
the default behavior from Object .
Equality and hash codes
If we override Object.equals , then we should override Object.hashCodes ,
and vice versa. Equality is simply a stronger test than the hash code, so
requirements for one but not the other are extremely rare.
The final modifier
The choice to use the final modifier is, well, final. Its use prohibits reuse of a
class, attribute, or method, so take special care in using it. Conventions you
might impose for final include:
Use final only for the declaration of constants.
Alternatively, allow guarded use of final , but only in cases where the
superclass defines the interface of all of the methods (disregarding
The Java language forces us to consider exceptions that might occur in our
programs, but it cannot force us to handle exceptions well. In Bitter Java , the
exception management is intentionally sparse. We do this to keep the examples
short and readable, but at the cost of failing to communicate good exception-
management practices. Here are a few rules of thumb:
Exceptions should provide logical, predictable behavior. For example, a
mistyped file name should not cause a dramatic stack trace and exit,
because this behavior is neither logical nor predictable.
Exceptions should be handled at a granular level. It is almost always
poor practice to handle a raw exception, since logical behavior cannot
be determined at this level.