Effective Java
Idioms and patterns for effective Java programming
June 6, 2001— At Tuesday’s “Effective Programming with Java Technology” conference session (TS-2425), Joshua Bloch, senior staff engineer from Sun Microsystems, presented some powerful, but not well known, idioms that should improve the effectiveness and quality of your Java programming. These idioms were taken directly from Bloch’s new book, Effective Java Programming Language Guide (Addison-Wesley, 2001).
Bloch’s session covered:
- The Static Factory pattern
- The Singleton pattern
- The Utility Class idiom
- The Typesafe Enumeration pattern
- Effective random number generation
The Static Factory pattern
When you want to create an instance of a class (an object), you normally do so by calling new
on the class’s constructor. As an alternative to new
, the Static Factory pattern provides a static method that returns an instance.
Bloch took the following example of a static factory straight from Java:
public static Boolean valueOf(boolean b) {
return (b ? Boolean.TRUE : Boolean.False);
}
This method appears in the java.lang.Boolean
class.
Static Factory pattern advantages
Bloch noted a number of advantages to using static factories instead of constructors to create objects.
First, static factories have names while constructors do not. Constructors must have the same name as the class and may vary only in their type and number of arguments. Static factories, on the other hand, can have different names, as well as any type and number of arguments. Bloch used an example of a complex number to drive this point home:
public static Complex valueOf(float re, float im) //...
public static Complex valueOfPolar(float r, float theta) // ...
In the code above, the static factory is much more expressive. Furthermore, the equivalent constructors would have conflicted with one another, since they would have the same number and argument types.
Second, Bloch explained that a static factory is not required to create a new object each time it is called. This means that you can reuse immutable objects and cache frequently used values (such as Boolean
‘s TRUE and FALSE). Such reuse can lead to improved performance. With static factories, you can also control and regulate which objects exist at any given time. You can’t do that with new
.
Finally, Bloch pointed out that static factories can return objects of any subtype. Creating an object using a constructor will only create objects of a specific type. Using a static factory in this way creates a nice separation between interface and implementation. Beyond supporting polymorphism, the ability to hide an object’s subtype is powerful. The class of the object that is returned need not be public, leading to compact, easier-to-understand APIs. The result: it’s easier to make changes to the API from release to release, and even during runtime.
Static Factory pattern disadvantages
As useful as it is, the static factory does have some disadvantages.
Bloch explained that a static factory cannot be subclassed. Normally, a static factory will make its constructor private so that other objects cannot instantiate it directly. However, Bloch maintained, this is a blessing in disguise, since inheritance is not always the best form of reuse anyway.
Bloch also cautioned that static factory methods are indistinguishable from other methods. To effectively use the pattern, you need to establish and follow an effective naming convention.
Bloch recommends that you employ the Static Factory pattern when you don’t need to subclass the class and one or more of the following proves true:
- Using the pattern will produce a significant performance gain
- You need the flexibility to return different types without the other objects needing to know the returned object’s true type
- You want to avoid making a class public
- You need control over the instances
The Singleton pattern
While every developer is familiar with the Singleton pattern, Bloch presented the pattern with a fresh, Java-centric approach. Here’s the example he used:
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
// ....
}
}
Indeed, there is and will be only one Elvis.
A singleton possesses no accessible constructor. Rather, it allows you to gain a reference to the singleton via a static final instance field. What makes the singleton interesting in Java is its serialization mechanism. If you are not careful, serializing an object can result in multiple instances!
Bloch presented a workaround. You can simply override readResolve()
as follows:
private Object readResolve() throws ObjectStreamException {
return INSTANCE;
}
The Utility Class idiom
A utility class contains only public static methods and is not meant to be instantiated. Utility classes are easily abused and can lead to procedural programming. However, Bloch pointed out two valid uses of this idiom. You should use a utility class to act on collections of primitives and collections of objects that implement interfaces. java.util.Collections
serves as an example of a properly designed utility class.
Utility classes take the following form:
public class UtilityClass {
// made private so cannot instantiate
private UtilityClass() {}
public static method() { /... and so on
}
The Typesafe Enumeration pattern
Java lacks an enumerated type. The Typesafe Enumeration pattern presents an alternative that replaces non-type safe constants with a type safe enumeration. Unfortunately, you cannot use these enumerations in switch statements.
For Bloch’s explanation on the Typesafe Enumeration pattern, see chapter five of his book, Effective Java Programming Language Guide.
Effective random number generation
Finally, Bloch recommended that developers use java.lang.Random
to create random numbers, as other procedures may not work effectively. Random
, added in Java 1.2, fixes some serious flaws found in the old random number generators.