Group for Software Engineering and Distributed Computing (DCS)
Department of Electronic, Computer, and Software Systems (ECS)
School of Information and Communication Technology (ICT)
Royal Institute of Technology (KTH)
Item 1: Consider providing static factory methods instread of constructs eg. A static factory method from the class Boolean, which translates a boolean primitive value into a Booleam object reference:
Advantages: a) unlike constructors, they have names. b) unlike constructors, they are not required to create a new object each time they're invoked. c) unlike constructors, they can return an object of any subtype of their return type. (Atten plz: in JDK 5.0, there is Covariant Return Types) Disadvantages: a) classes without public or protected constructors cannot be subclassed. b) they are not readily distinguishable from other static methods. two names for static factory methods are becoming common: valueOf --- Return an instance that has, loosely speaking, the same value as its parameters. getInstance --- Return an instance that is described by its parameters but cannot be said to have the same value.
Item 2: Enforce the singleton property with a private constructor One approach, the public static member is a final field:
// Singleton with final field publicclass Elvis { publicstaticfinal Elvis INSTANCE =new Elvis(); private Elvis() { } // Remainder omitted }
A second approach, a public static factory method is provided instead of the public static final field:
// Singleton with static factory publicclass Elvis { privatestaticfinal Elvis INSTANCE =new Elvis(); private Elvis() { } publicstatic Elvis getInstance() { return INSTANCE; } // Remainder omitted }
Item 3: Enforce noninstantiability with a private constructor Attemping to enforce noninstantiablity by making a class abstract does not work. A class can be made noninstantiable by including a single explicit private constructor:
// Noninstantiable utility class publicclass UtilityClass { // Suppress default constructor for noninstantiability private UtilityClass() { // This constructor will never be invoked } // Remainder omitted }
Item 4: Avoid creating duplicate objects An object can always be reused if it is immutable. As an extreme example of what not to do:
String s =new String("silly"); // DON'T DO THIS!
The improving version is simply the following:
String s ="No longer silly"
You can often avoid creating duplicate objects by using static factory methods (Item 1) in preference to constructors on immutable classes that provide both.
publicclass Person { privatefinal Date birthDate; // Other fields omitted public Person(Date birthDate) { this.birthDate = birthDate; } // DON'T DO THIS! publicboolean isBabyBoomer() { Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); Date boomStart = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); Date boomEnd = gmtCal.getTime(); return birthDate.compareTo(boomStart) >=0 && birthDate.compareTo(boomEnd) <0; } }
The isBabyBoomer method unnecessarily creates a new Calendar, TimeZone, and two Date instances each time it is invoked. The version that follows avoids this inefficiency with a static initializer:
class Person { privatefinal Date birthDate; public Person(Date birthDate) { this.birthDate = birthDate; } /** *//** * The starting and ending dates of the baby boom. */ privatestaticfinal Date BOOM_START; privatestaticfinal Date BOOM_END; static{ Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); BOOM_START = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); BOOM_END = gmtCal.getTime(); } publicboolean isBabyBoomer() { return birthDate.compareTo(BOOM_START) >=0 && birthDate.compareTo(BOOM_END) <0; } }
Item 5: Eliminate obsolete object reference
// Can you spot the "memory leak"? publicclass Stack { private Object[] elements; privateint size =0; public Stack(int initialCapacity) { this.elements =new Object[initialCapacity]; } publicvoid push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size ==0) thrownew EmptyStackException(); return elements[--size]; } /** *//** * Ensure space for at least one more element, roughly doubling the capacity * each time the array needs to grow. */ privatevoid ensureCapacity() { if (elements.length == size) { Object[] oldElements = elements; elements =new Object[2* elements.length +1]; System.arraycopy(oldElements, 0, elements, 0, size); } } }
If a stack grows and then shrinks, the objects that were popped off the stack will not be garbage collected, even if the program using the stack has no more references to them. This is because the stack maintains obsolete references to these objects.
public Object pop() { if (size==0) thrownew EmptyStackException(); Object result = elements[--size]; elements[size] =null; // Eliminate obsolete reference return result; }
Item 6: Avoid finalizers Nothing time-critical should ever be done by a finalizer. You should never depend on a finalizer to update critical persistent state. Explicit termination methods are often used in combination with the try-finally construct to ensure prompt termination.
Foo foo =new Foo(); try{ // Do what must be done with foo }finally{ foo.terminate(); // Explicit termination method }
It is important to note that “finalizer chaining” is not performed automatically. If a class (other than Object) has a finalizer and a subclass overrides it, the subclass finalizer must invoke the superclass finalizer manually.
Instead of putting the finalizer on the class requiring finalization, put the finalizer on an anonymous class (Item 18) whose sole purpose is to finalize its enclosing instance. A single instance of the anonymous class, called a finalizer guardian, is created for each instance of the enclosing class.
// Finalizer Guardian idiom publicclass Foo { // Sole purpose of this object is to finalize outer Foo object privatefinal Object finalizerGuardian =new Object() { protectedvoid finalize() throws Throwable { // Finalize outer Foo object } }; // Remainder omitted }