J
oshua
Bloch's
Effective Java Programming Language Guide
is the Java book
that James Gosling recommended to conference-goers during his keynote address
at
JavaOne
2001
in San Francisco this year. ("I sure wish I had had this book
ten years ago. Some might think that I don't need any Java books, but I
need this one," he said.) For this reason the book gets a lot of attention.
Accordingly high are people's expectations. Let's see whether the book
keeps the promise of being "an excellent book, crammed with good advice
on using the Java programming language and object-oriented programming
in general," per Java Language Specification author Gilad Bracha on the
back cover.
Effective
Java Programming Language Guide
is a second-generation title that picks
up the thread where conventional introductions to Java end. Other titles
that are in the same league as this one include
Java
in Practice
by Nigel Warren and Philip Bishop,
The
Elements of Java Style
by Allan Vermeulen et.al., and
Practical
Java
by Peter Haggar. These books provide advice on proper use
of the language and require familiarity with the language and part of the
JDK. Clearly, these are not books for Java novices.
The
format of Bloch's book is borrowed from Scott Meyers'
Effective C++
books: the text is broken down into a number of items, each of which discusses
a certain pitfall in the language accompanied by a recommendation on how
to avoid common errors.
We
can say upfront that this
is
an excellent book. In fact, compared
to other books in the same league, this is one of the best so far. Its
predecessors suffer from the fact that they were written a while ago. For
instance, they provide advice on how to manually perform code optimizations
for better performance. (Nowadays the Java compilers do this automatically,
so this advice is mostly obsolete.)
In
addition,
Effective Java Programming Language Guide
covers a broader
range of topics than most other books. Here is what the chapters are about:
-
"Creating
and Destroying Objects": Here you'll find, among other advice, the recommendation
to eliminate unwanted references and avoid finalizers.
-
"Methods
Common to All Objects": This is one of the most important chapters in the
book because every Java programmer needs to know how to implement these
common methods correctly. Bloch suggests implementations of equals, hashCode,
toString, clone, and compareTo. This chapter also contains a number of
contentious issues, which I describe later.
-
"Classes
and Interfaces": Important design issues such as immutability and inheritance
vs. delegation are discussed in this chapter.
-
"Substitutes
for C Constructs": This chapter is of interest predominantly to Java programmers
with a C background. It suggests, for instance, replacements for unions,
which hardly any Java programmer with an OO background would ever use.
-
"Methods":
Here you'll find such advice as how to use overloading judiciously.
-
"General
Programming": Most of the advice provided in this chapter is more or less
common sense. Here you'll find rules such as "adhere to generally accepted
naming conventions" and "avoid strings where other types are more appropriate."
-
"Exceptions":
The author discusses a number of issues related to exceptions that readers
(depending on their background) might be familiar with from using exceptions
in other programming languages.
-
"Threads":
This chapter covers a number of important issues related to the use of
multiple concurrent threads in Java. Some of them will be obvious to programmers
experienced in concurrent programming; other items are difficult to understand
without a more intimate knowledge of the intricacies of the Java memory
model.
-
"Serialization":
This chapter provides advice on proper implementation of the Serializable
interface.
One strength
of
Effective Java Programming Language Guide
is that it does not
pretend that the Java programming language or its libraries are flawless.
Bloch frankly concedes that Java library classes occasionally do not set
good examples, and even break the rules that he sets up in his book. This
dispassionate view of the language and its library contributes greatly
to the value of this book. However, he displays a more biased view in other
areas.
Take,
for instance, his position on the use of inheritance. Inheritance is a
language and design feature typical of object-oriented programming languages
that can be used in different ways and for several purposes. It is beyond
the scope of this review to discuss these various paradigms. Suffice it
to say that there is not just one way of using inheritance. But Bloch recommends
one specific view to inheritance in Java. According to him, when you want
to add fields to a class that represents a value type, and the added fields
would be used in an implementation of equals(), you should not use inheritance.
Instead, he recommends that you use delegation.
This
is a legitimate view to inheritance and Bloch consistently sticks to it
throughout the book. If you follow his recommendations and avoid the above-mentioned
kind of inheritance, then the advice he gives in Chapter 2 on proper implementation
of equals() and compareTo() is valid and useful advice. However, there
is nothing in the Java programming language that discourages or bans this
type of inheritance, nor is it unusual to use this kind of inheritance
in object-oriented design in general. Under certain circumstances, it cannot
even be avoided; this is because delegation is different from inheritance.
(For instance, delegation cannot replace inheritance if a protected method
must be overridden.) If you cannot or do not want to avoid the critical
type of inheritance, you must not implement equals() and compareTo(), as
he suggests in Chapter 2, because these implementations are nontransitive
and incorrect in this particular situation. Bloch does not address this
exceptional situation and does not provide an alternative implementation
of equals() and compareTo(). His book just says to avoid the situation:
do not use inheritance in this particular way, at least not in Java.
We
do not necessarily see this simplistic advice as a weakness of
Effective
Java Programming Language Guide
. Full coverage of the topic, including
all alternatives, would have been beyond the scope of the book. However,
readers should keep in mind that it makes a lot of sense to consult alternative
publications in order to acquire enough knowledge to make an informed decision.
The advice provided in
Effective Java Programming Language Guide
is valuable, but it is not the whole story. Java is a hybrid language that
draws from various sources and combines several paradigms; it is not the
author's fault that for practically every position there is a counter argument
and a different way of seeing and doing it.
Our
advice to the reader, therefore, is to read
Effective Java Programming
Language Guide
and
other books, put the various pieces of advice
into perspective, and decide for yourself which recommendation you want
to follow in your own Java programs. For alternative advice, see Peter
Haggar's book
Practical Java
or
Mark
Davis' articles
in
Java Report
. Also,
Program
Development in Java
by Barbara Liskov has interesting things to
say about identity, similarity, and equality of objects.
By
the way, studying Bloch's book is worth the time for a yet another reason,
beyond seeking advice: he was involved in the development of the Java platform
libraries and, in particular, the collection framework. What he describes
in his book is based on his experience implementing a reusable set of library
classes and interfaces, and it reflects the design decisions made for this
framework. For this reason his book gives invaluable insight into the design
of the Java collection classes and interfaces that you won't find anyplace
else.
How
does
Effective Java Programming Language Guide
compare to Scott
Meyers'
Effective C++
, from which it borrows the title and form?
Effective
C++
reflects commonly-agreed-upon C++ wisdom. This is different from
Effective
Java Programming Language Guide
, which is more like one piece in the
puzzle?a good one, a real jewel, yet just one of them. In many areas there
is no such thing as "commonly-agreed-upon Java wisdom." The topic of inheritance
use and equals() implementation nicely illustrates this point: open different
books and you'll find different positions about it. This ambiguity is a
feature of Java, not a flaw of the respective publications. The same is
true of
Effective Java Programming Language Guide
: it is an excellent
book and a must-read for serious Java programmers, but there is room for
disagreement and alternative approaches to using Java.
Angelika
Langer
develops and teaches classes on Java, C++, multithreading, and
internationalization. She is an internationally recognized speaker and
served on the ANSI/ISO C++ Committee from 1993 to 1998.
Klaus Kreft
is a software architect and senior consultant with 15+ years of experience
in industrial software development. He currently works for Siemens Business
Services in Germany. Langer and Kreft are authors of "Standard C++ IOStreams
and Locales" (Addison-Wesley, 2000) and are columnists for the C/C++ Users
Journal.
|