Effective Java (First Edition) Companion

Joshua Bloch's much awaited (second) Effective Java book is scheduled to arrive in few weeks. Joshua has done favors to millions of programmers by distilling his knowledge of Java programming language (and programming in general) in his first Effective Java Book (published by Addison Wesley).

Effective Java: Cover PageI just thought of providing a cheat-sheet for this book so that programmers can refer to it (link to it) while programming, reviewing code, thinking etc. This text is neither a replacement of the actual book nor is it a mere copy of contents in it (which I have read and referred to, several times). It is more of my understanding and reflection of the entire book, although I have heavily depended on the actual text for it is impossible to come up with alternate explanation of any concept explained in this book. Joshua's deep understanding of the language, excellent choice of words, tenacious following of the Java Language Specification, clear and concise manner of explanation makes this book a great reference. Thanks Joshua, for your insights. It is also obvious that Joshua rates API design and clarity in programming higher than performance considerations. It is striking that great programmers think alike:

Premature optimization is the root of all evil.

Although this book was written with J2SE 1.4 SDK in mind (Boy! it is already years old), the material applies well even to Java SE 6. I created this e-reference so that it would make a good read while we wait for Joshua's second book (and hopefully thereafter).

Learning the art of programming, like most other disciplines, consists of first learning the rules and then learning when to violate them. - Joshua Bloch.

I initially thought of creating it as a Wiki topic but then decided against it. A companion Wiki is created here and this document is highly anchored. I haven't gone through several editorial and correctness iterations of the text here, and rely on programmers at large to enhance and possibly correct the contents. Interested readers can comment on the Wiki by linking to the anchors from here. The anchors in this document are listed here.

Item List

Item List
ID (Linked to discussion) Item Related Items (From this book, JLS etc.)
1. Consider providing static factory methods instead of constructors. 13 02 21 34 14
2. Enforce the singleton property with a private constructor. 10 57 21 03
3. Enforce noninstantiability with a private constructor. 02 15
4. Avoid creating duplicate objects.

13 JLS-3.10.5 01 37 48

24(Counter Item) 32

5. Eliminate obsolete object references. 29
6. Avoid finalizers. JLS-12.6
12. Minimize the accessibility of classes and members. JLS-6.6 18 19
13. Favor Immutability. 04 10 24
14. Favor composition over inheritance. 15
15. Design and document inheritance or else prohibit it.

10 14 54 13 16

 

Item Discussion

Item Discussion
ID (Linked to list) Discussion // DON'T DO THIS!
1.

Consider providing static factory methods instead of constructors.

This technique has both advantages and disadvantages. To favor composition over inheritance though, having static factory methods is advisable.

Advantages:

  • Factory methods have names and as such they can be more expressive. Limitations of method overloading can be eliminated by explicitly named methods. Constructors don't enjoy that freedom.
  • They don't have to return a new instance of the class unlike constructors.
  • They can return an instance of any (even nonpublic) subtype of a given type. This facilitates the backing-store-reuse or view pattern and promotes interface-based frameworks (e.g. Java Collections Framework).

Disadvantages:

  • It favors composition over inheritance as a class can't be subclassed if it does not have a non-private constructor.
  • Usually a naming convention has to be followed if these methods have to stand out as factory methods. The current conventions are: getInstance() and valueOf(SomeOtherType).
 
2.

Enforce the singleton property with a private constructor.

The topic of Singletons is under scrutiny by developer community. It's clearly an overused pattern. Developers should think hard to justify the need for Singletons. It has somehow become a deplorable norm to create Singletons without justification and at times implement them incorrectly.

But first, the following discusses two ways of implementing Singletons correctly (under normal circumstances) should the need for them be justified:

First: This is correct, straightforward and should generally be employed.

public class MySingleton {
  private static final MySingleton INSTANCE = new MySingleton();
  /*essential to make this private*/
  private MySingleton() {
    // this can possibly delay class loading, but that's OK
  }
  public static getInstance() {
    return INSTANCE;
  }
  // implement readResolve() method if this class needs to be Serializable
}

Second:

public class MySingleton {
  private static MySingleton INSTANCE = null;
  /*essential to make this private*/
  private MySingleton() {
    // this can possibly delay class loading, but that's OK
  }
  public synchronized static getInstance() {
    // this results in lock contention, but it is correct
    if (INSTANCE == null) {
      INSTANCE = new MySingleton();
    }
    return INSTANCE;
  }
  // implement readResolve() method if this class needs to be Serializable
}

There are other techniques like lazy initialization, but you have to be extremely careful with them. The first technique above is by far the best way of defining Singletons.

Few good references on this topic:

Never be over-smart with implementing something as trivial as correct Singleton pattern. This results in insidious issues with thread safety of your program because of the so-called broken Double-checked locking idiom:

//Don't Do This
public class OverSmart { 
private OverSmart os = null;
public OverSmart getInstance() {
if (os == null) {
synchronized(this) {
if (os == null) {
os = new OverSmart();
}
}
}
return os;
}

// other members...
}
3.

Enforce noninstantiability with a private constructor.

A class can be made noninstantiable only by providing a single explicit private constructor. Note that noninstantiability of a class can't be guaranteed by making it abstract.

Another technique I have seen is to create a parameterless public constructor that throws a RuntimeException. But this is not an effective code pattern because it does not make the intent of the programmer explicit.

For API or library designers, it is a good idea to make a class noninstantiable if it is a mere collection of utility static methods.

 //Don't Do This
public class  YouCantCreateMe {
   public YouCantCreateMe() {
      throw new RuntimeException("Sorry");
   }
 }
4.

Avoid creating duplicate objects.

Quoting Joshua: "Reuse can be both faster and more stylish".

Following the intent of this item requires sound judgment. There are quite a few considerations and counter-arguments that a programmer has to contemplate while following what has been said here.

Note that reuse here refers to functionally equivalent objects. In other words, there is a potential to reuse existing objects in lieu of new ones, if the new ones are functionally equivalent to existing ones.

In order to take benefits of object reuse, one should carefully study the immutable classes and use them whenever possible as they always promote reuse through functional equivalence. Making a class immutable however, needs thorough analysis.

More subtle cases involve reusing the objects when they are mutable. These are more complex cases to analyze. For example, a profiling session tells you that you are calling a method hundreds of times and that this method unnecessarily creates invariant objects every time it is called. In that case, again, after thorough analysis, you can optimize the use of existing objects by facilitating reuse.

//Don't Do This
 String s = new String("silly");
//The argument to the String constructor ("silly") is itself a 
//String instance, functionally identical to all of the objects //created by the constructor.
5.

Eliminate obsolete object references.

Myth for novice programmers: Java (programs written in Java) has no memory leaks.

Although Java manages the memory required for our programs, it can not understand what we want to do. If we are holding onto an object by maintaining a reference to it, it is obvious that Java thinks that we want to do that. This means that as programmers, it is our prime responsibility to not hold onto references that are obsolete. Holding onto obsolete references constitutes memory leaks in Java. This is also termed as unintentional object retention.

Nulling out a reference to remove obsolete references to an object is good, but one must not overdo it. The best way to eliminate an obsolete reference is to reuse the variable in which it was contained or to let it fall out of scope.

Generally speaking, whenever a class manages its own memory, the programmer should be alert for memory leaks. Whenever an element is freed, any object references contained in the element should be nulled out -- Don't confuse this with the previous paragraph. You don't have to necessarily null out the references if the variable falls out of scope.

Because memory leaks typically do not manifest themselves as obvious failures, they may remain present in a system for years. -- This is why they are subtle to find out and remove. Programmers need heap profilers to diagnose such silent killers.

 
6.

Avoid finalizers.

"Finalizers are unpredictable, often dangerous, and generally unnecessary. Their use can cause erratic behavior, poor performance, and portability problems."

Frankly, I have never used finalizers and hence I don't have much to add to this discussion. It is worth noting that depending on execution of finalizers is a bad decision nevertheless.

Providing and making clients of your code call a termination or resource reclamation method leads to much cleaner API. Examples are: close() method on several java.io classes.

A legitimate use of finalizers arises when you feel the need of a safety net because the clients may not do the due diligence and resources are not reclaimed. Obviously, finalizers are not the best solution for this (owing to previous discussion), but that is the only way.

Another reason for their use is in case of classes that have native peers. Remember however that native peers must not hold critical resources to be reclaimed in a finalizer.

The rules of thumb are:

  • Don't use finalizers yet. If you have to claim critical resources promptly, explicit termination method (that clients should call) is the only right hook for that.
  • "The termination method should do whatever is required to free the critical resource. The termination method can be a native method, or it can invoke one."
  • If you override finalize(), then it is a good practice to manually call super.finalize() since chaining of finalizers is not automatic. Object.finalize() simply returns (is a no-op).

Finally, Joshua suggests a finalizer guardian idiom for a nonfinal public class that guards against a malicious subclass that fails to call super.finalize() failing to give your class a chance to finalize. This idiom is used in java.util.Timer class. A finalizer guardian's (which is an instance of anonymous inner class) sole purpose (at the cost of its existence) is to call the enclosing instance's finalize() method.

A quick check on GlassFish codebase reveals that there are several finalizers and I am not quite sure if all of them are called for.

 
12.

Minimize the accessibility of classes and members.

Benefits of information hiding (encapsulation) and separating interfaces from implementation are obvious. Java provides several facilities to hide the internals of a module. This results in clean design and modules can be tested, changed without affecting the correctness of the entire system since modules rely on each other's API. Don't confuse information hiding with the subtle topic of Method Overloading-Method Overriding-Field Hiding.

Access Control Mechanism in Java should be carefully studied. From this standpoint, (top-level) classes and members are the two broad categories of interest. As of Java SE 5.0 and Java SE 6, packages are the only way to sand-box code organized into classes and interfaces. The natural way to design large bodies of code is to first define the API and then define packages, then interfaces and classes and then implement the methods and fields considering access specification at every step. To achieve this, it is best to start with the most protected access and then relax it, till you achieve required accessibility.

The rule of thumb is that you should make each class or member as inaccessible as possible.

The default access is implied by the absence of any specifier on a given entity. Thus, a top-level class (and interface) is either public which means it is seen by the universe or it is package-private which means by default, only other classes and interface in the same package can see it. This is the first entry point as far as access is concerned.

If a package-private top-level class or interface is used only from within a single class, you should consider making it a private nested class (or interface) of the class in which it is used (Item 18).

A member can have one of private (accessible only from within the class) , package-private (default, accessible from within any class in the same package), protected (mostly accessible from any subclass anywhere and from within the package) and public (accessible from anywhere) access specifiers. An important conclusion is that the protected access specifier is less protected than the default access, don't place a protected access specifier in an attempt to protect a member of a class. Thus, if you are unsure of accessibility, start with private, followed by package-private.

Public variables should be avoided as they result in exposing the internal representation of the data and are hard to replace by something else. An exception here is the definition of constants. Constants should always be instances of either primitive types or immutable classes. "A final field containing a reference to a mutable object has all the disadvantages of
a nonfinal field."

Note that a nonzero-length array is always mutable, so it is nearly always wrong to have public static final array field.

To summarize, optimizing access specification is like tightening the screws leaving tolerance that is just enough, eliminating extraneous words in a sentence, paragraphs in a chapter and so on.

//Don't Do This
class Base { 
    public static final String NAME = "Base";
    // Hiding/Shadowing is not advisable
}
class Derived extends Base {
    public static final String NAME = "Derived";
}

//Potential security hole! 
public static final Type[] VALUES =  { ... };

13.

Favor Immutability.

An immutable class is simply a class whose instances cannot be modified. An immutable object can be in exactly one state, the state in which it was created.

Follow this recipe to impart immutability to classes.

Immutable objects are simple and inherently thread-safe; they require no synchronization since there are no state changes that they go through.

It is appropriate to share the internals of immutable objects with other objects if there is no way to modify them. Generally speaking, the internals of an immutable object are comprised of immutable objects.

Ways to make an object immutable in addition to following the recipe:

  1. Make the class final. Make the class non-final but make all the methods final, leaving the room for extension. This means you have to undertake the responsibility of defending against malicious subclasses.
  2. Make the constructors private (or package-private) and provide static factory methods.

It is an oversight that BigInteger and BigDecimal classes are not final. You should always make value classes immutable. To reduce the performance overhead, you can think of a package-private mutable companion class that an immutable class uses to speed up multistep operations. If predicting what can be done with an immutable class is not possible, make this companion class public (for example, java.lang.String and java.lang.StringBuffer).

 
14.

Favor composition over inheritance.

Implementation Inheritance is dangerous with classes not designed for that. This is mainly because the superclass implementation of overridden methods may change from release to release and break the subclasses even if their (of subclasses) implementation has not changed.

To quote Joshua:

A related cause of fragility in subclasses is that their superclasses can acquire new methods in subsequent releases.

Surprising things may result if you rely on the implementation of behavior in superclasses. This is especially so for classes that are not designed for extension. The effect is pronounced when when you use overriding.

An alternate technique uses composition and employs the decorator or forwarding design pattern. The idea is to make an implementation a private member of your class and forward requests of common interface to that member. This is likely to make your implementation more robust.

<personal-problem>
The inheritance-composition dilemma usually takes some toll on me. Composition is likely to provide more robust design -- does it mean that when programmers are not sure about extensibility of implementation, they should make all implementations final?

On the other hand, we have some examples where inheritance is used effectively and composition is considered at least tedious or procedural.

</personal-problem>

Inheritance is appropriate only when a genuine subtype relationship exists between the subclass and the superclass.

According to Joshua:

There are a number of obvious violations of this principle in the Java platform libraries. For example, a stack is not a vector, so Stack should not extend Vector. Similarly, a property list is not a hash table so Properties should not extend Hashtable. In both cases, composition would have been appropriate.

 
15.

Design and document (for) inheritance or else prohibit it.

(Editorial comment: As the perhaps only case, I thought for is not required in this item's synopsis).

Perhaps this item tries to minimize the dilemma about when to choose inheritance.

Documentation of how a class uses its overridable methods in the /**doc comments */ of a method is a must. This helps users of the API to understand the implications of overriding methods. This is called documenting self-use of the class.

This is where (I feel) the art part of programming comes into picture (again), since there is no recipe to follow.

There are a few more restrictions that a class must obey to allow inheritance. Constructors must not invoke overridable methods, directly or indirectly. If this rule is violated, it is likely that program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, then the method will not behave as expected.

Note that if you violate the above, a final field can be observed in two different states by a program!

It's generally not a good idea for classes designed for extension to implement Cloneable or Serializable interfaces. If they do, they should follow certain restrictions:

Neither clone nor readObject may invoke an overridable method, directly or indirectly.

This is where the implementation of a class becomes part of public interface of a class. This is because if you have designed a Serializable class for extension, you have to make readresolve() or writeReplace() methods protected or else they are silently ignored by the subclasses while (de)serializing.

Since this is rather confusing, I am going to quote Joshua, as I can't do any better --

The best solution to this problem is to prohibit subclassing in classes that are not designed and documented to be safely subclassed. There are two ways to prohibit subclassing. The easier of the two is to declare the class final. The alternative is to make all the constructors private or package-private and to add public static factories in place of the constructors. This alternative, which provides the flexibility to use subclasses internally, is discussed in Item 13. Either approach is acceptable.

This advice may be somewhat controversial, as many programmers have grown accustomed to subclassing ordinary concrete classes to add facilities such as instrumentation, notification, and synchronization or to limit functionality. If a class implements some interface that captures its essence, such as Set, List, or Map, then you should feel no compunction about prohibiting subclassing. The wrapper class pattern, described in Item 14, provides a superior alternative to inheritance for altering the functionality.

This item concludes by providing a technique of moving the self-use of a class's overridable methods to its private helper method.

 
     

Notes

Method Overloading-Method Overriding-Field Hiding

Firstly, overloading applies to methods alone (of course, in Java). Overriding too, applies to methods alone. The (far fetched) field-equivalent of method overriding is called hiding or shadowing. In other words, a subclass can only shadow a member variable and it is a practice that should not be used at all. The consequences of not following this advice (even inadvertently) are dire. To some extent, the provision of shadowing is just a side effect of language implementation and programmers should think that there is no point in redefining the variable (in a subclass) with a name that is taken by one of its super classes. Complexity increases when the variables participating in shadowing differ in type, value, both type and value, one being static and other being instance.

Overloading and overriding (of methods) on the other hand, are a usual practice and there are scenarios when these techniques are appropriate. Even then, overloading should be used more cautiously. At first, it may seem that naming a behavior of a class by a single verb is appropriate, but experience shows that naming methods explicitly (or, uniquely) is more expressive and maintainable than overloaded methods (with same names and slightly differing parameter lists). Overloading is a compile-time phenomenon and compiler generates the code to bind a call to the given overloaded method with a given method. The run-time type of method's parameters does not affect the choice of overloading. As a rule, don't overload methods if they take same number of parameters. It's also messy (impossible?) when the parameters are of same type, but convey something completely different.

Overriding is a more widely used procedure. It is the language mechanism to support the so-called polymorphism, where a subclass modifies a (super) class's behavior identified by a method with a given name. A subtle characteristic of Java's method overriding is that this decision is made dynamically (based on the run-time type of the object on which the method is invoked) and that it is impossible to call super class's implementation of an overridden method on an instance of a subclass (except from within subclass using the keyword super). Another consequence of using overriding is that an overridden method should have access specification that is no less restrictive than what is specified in the nearest super class that provides its implementation. This leads us into Liskov's Substitution Principle which states that anything that can be done with an instance of a class can also be done with an instance of any of its subclasses. (This is true with interface-based programming as well. In other words, since all the methods in a Java interface are public by default, all the classes implementing the interface must have their public implementations).

Java 5 introduces an annotation, @Override to denote a method definition that overrides it in a subclass. Compiler ensures that use of @Override is correct (a compiler . Perhaps it was a good idea to provide @Overload annotation as well.

Functional and Procedural Programming

Methods of a well-written Immutable class follow functional approach because methods return the result of applying a function to their operand without modifying it. Contrast this with the more common procedural approach in which methods apply a procedure to their operand causing its state to change. Functional programming enables Immutable classes.

Recipe for Writing Correct Immutable Classes

1. Don't provide any methods that modify the object (known as mutators).


2. Ensure that no methods may be overridden. This prevents careless or malicious subclasses from compromising the immutable behavior of the class. Preventing method overrides is generally done by making the class final.


3. Make all fields final. This clearly expresses your intentions in a manner that is enforced by the system. Also, it may be necessary to ensure correct behavior if a reference to a newly created instance is passed from one thread to another without synchronization, depending on the results of ongoing efforts to rework the memory model.


4. Make all fields private. This prevents clients from modifying fields directly. While it is technically permissible for immutable classes to have public final fields containing primitive values or references to immutable objects, it is not recommended because it precludes changing the internal representation in a later release (Item 12).


5. Ensure exclusive access to any mutable components. If your class has any fields that refer to mutable objects, ensure that clients of the class cannot obtain references to these objects. Neither initialize such a field to a client-provided object reference nor return the object reference from an accessor. Make defensive copies (Item 24) in constructors, accessors, and readObject methods (Item 56).

History

0.1 04 September 2007 km@dev.java.net (केदार Mhaswade) Created document, described Chapter 2.
0.2 11 September 2007 km@dev.java.net (केदार Mhaswade) Added notes, item #12, #13.
0.3 11 November 2007, km@dev.java.net (केदार Mhaswade) Added notes, item #14, #15.

Anchors in This Document

Introduction
  1. Quote about Programming
Item Glossary
  1. Item 1
  2. Item 2
  3. Item 3
  4. Item 4
  5. Item 5
  6. Item 6
  7. Item 7
  8. Item 8
  9. Item 9
  10. Item 10
  11. Item 11
  12. Item 12
  13. Item 13
  14. Item 14
  15. Item 15
  16. Item 16
  17. Item 17
  18. Item 18
  19. Item 19
  20. Item 20
  21. Item 21
  22. Item 22
  23. Item 23
  24. Item 24
  25. Item 25
  26. Item 26
  27. Item 27
  28. Item 28
  29. Item 29
  30. Item 30
  31. Item 31
  32. Item 32
  33. Item 33
  34. Item 34
  35. Item 35
  36. Item 36
  37. Item 37
  38. Item 38
  39. Item 39
  40. Item 40
  41. Item 41
  42. Item 42
  43. Item 43
  44. Item 44
  45. Item 45
  46. Item 46
  47. Item 47
  48. Item 48
  49. Item 49
  50. Item 50
  51. Item 51
  52. Item 52
  53. Item 53
  54. Item 54
  55. Item 55
  56. Item 56
  57. Item 57
Item Discussion
  1. Item - 1 Discussion
  2. Item - 2 Discussion
  3. Item - 3 Discussion
  4. Item - 4 Discussion
    1. Silly String Constructor
  5. Item - 5 Discussion
  6. Item - 6 Discussion
    1. Rules of Thumb for Finalizers
  7. Item - 7 Discussion
  8. Item - 8 Discussion
  9. Item - 9 Discussion
  10. Item - 10 Discussion
  11. Item - 11 Discussion
  12. Item - 12 Discussion
    1. Don't Shadow (Hide) Variables
    2. Functional and Procedural Programming
    3. Recipe to Impart Immutability to Classes
  13. Item - 13 Discussion
  14. Item - 14 Discussion
  15. Item - 15 Discussion
  16. Item - 16 Discussion
  17. Item - 17 Discussion
  18. Item - 18 Discussion
  19. Item - 19 Discussion
  20. Item - 20 Discussion
  21. Item - 21 Discussion
  22. Item - 22 Discussion
  23. Item - 23 Discussion
  24. Item - 24 Discussion
  25. Item - 25 Discussion
  26. Item - 26 Discussion
  27. Item - 27 Discussion
  28. Item - 28 Discussion
  29. Item - 29 Discussion
  30. Item - 30 Discussion
  31. Item - 31 Discussion
  32. Item - 32 Discussion
  33. Item - 33 Discussion
  34. Item - 34 Discussion
  35. Item - 35 Discussion
  36. Item - 36 Discussion
  37. Item - 37 Discussion
  38. Item - 38 Discussion
  39. Item - 39 Discussion
  40. Item - 40 Discussion
  41. Item - 41 Discussion
  42. Item - 42 Discussion
  43. Item - 43 Discussion
  44. Item - 44 Discussion
  45. Item - 45 Discussion
  46. Item - 46 Discussion
  47. Item - 47 Discussion
  48. Item - 48 Discussion
  49. Item - 49 Discussion
  50. Item - 50 Discussion
  51. Item - 51 Discussion
  52. Item - 52 Discussion
  53. Item - 53 Discussion
  54. Item - 54 Discussion
  55. Item - 55 Discussion
  56. Item - 56 Discussion
  57. Item - 57 Discussion

Notes

  1. Note-1: Method Overloading, Overriding and Field Hiding
  2. Functional and Procedural Programming
  3. How to Make a Class Immutable