Tuesday, November 06, 2012

Part I - Effective Java - Creating and Destroying Objects

This will be a series of posts based on the book Effective Java by Joshua Bloch. The posts will be split into the following parts based on the chapters in the book.

  1. Creating and Destroying Objects
  2. Methods Common to All Objects
  3. Classes and Interfaces
  4. Substitutes for C Constructs
  5. Methods
  6. General Programming
  7. Exceptions
  8. Threads
  9. Serialization

This post will cover Creating and Destroying Objects


Providing static factory method

Consider providing static factory methods in the object to create instances of the class.

Benefits

1.       Methods can be named to indicate the type of object that is being returned. This will avoid the problem where it is found necessary to have two constructors having the same signatures, but different parameters.
2.       Factory methods do not need to construct an instance each time they are invoked. This can be useful in limiting the number of object instances of a class created in the JVM. This can be used to create immutable classes. E.g. factory methods the Boolean class can be used to ensure that only two objects of type Boolean ever exist in the JVM. Additional advantage is if a == b also means a.equalsEvery method expects a (b) and the performance of == can be significantly better than ==.
3.       Factory methods need to return the same class, but can return any object which is a subtype of the return type.  This can be used to hide classes in libraries. Only the interface will be exposed to the outside world.

Disadvantages

  1. 1.       Classes without public or protected constructors cannot be subclassed.
  2. 2.       The methods used to create instances of class are not distinguishable from other methods of the class. It can be difficult to identify such methods easily in a class.

Examples

The collections class java.util.Collections can be used to instantiate a variety of Collection classes. The Java Cryptographic Extension uses this method to allow instantiation of the multiple implementation of the APIs.

Enforce Singleton Pattern with a private Constructor

A singleton is a class which has only one instance in the JVM.
There are two ways to create a Singleton
public class FirstSingleton {
    public static final FirstSingleton INSTANCE = new FirstSingleton();
    private FirstSingleton () {
    }
}
public class SecondSingleton {
    private static final SecondSingleton INSTANCE = new SecondSingleton ();
    private SecondSingleton () {
    }
    public static SecondSingleton getInstance() {
        return INSTANCE;
    }
}
The advantage of the second method is that if in a future date one wishes to convert the object from a Singleton to Multiton it will be possible without changing any references to this object. This will be near impossible if one adopts the first pattern.
If we wish to make a Singleton class Serializable then just implementing the interface will not be sufficient, one will need to implement the readResolve method too so that multiple instances of the class are not created.

Enforce noninstantiability with a private constructor

Sometimes there is a requirement for a class which has only static methods and constants. Typically utility classes will fall under this category.
For such classes one should define a private constructor so that this can never be instantiated. If this private constructor is not defined then it will be possible to instantiate this class which does not make sense.
This will also prevent the class from being subclassed.

Examples

1.       java.util.Arrays
2.       java.util.Math
3.       java.util.Collections

Avoid creating duplicate objects

When objects are immutable it makes sense to use the same instance of the object rather than creating a new instance.
E.g.
String s = new String(“silly”); //Don’t do this.
This unnecessarily creates another instance of the String whereas the following would have sufficed.
String s = “silly”;
Any object that needs to contain a constant value should be defined once and reused instead of being instantiated again and again. E.g. fixed dates against which some other dates must be compared.
Note: Creating objects is not very expensive but they should be created only when required or when it makes sense to create objects to keep the code simple and clear.
Maintaining an object pool is a bad idea unless the objects are real heavy weights, i.e. creation of these objects are expensive. One example of such an object is the Database Connection.
Be careful and do not reuse an object which should not be. Typically objects that can change should not be reused, instead a new instance or a copy should be made.

Eliminate obsolete object references             

Objects that are no longer required, but may not be Garbage Collected by virtue of it going out of scope should be nulled so that they can be garbage collected.
Consider the following example which is an implementation of Stack:
public class Stack {
    private Object[] elements;
    private int size = 0;
    public Stack (int initialCapacity) {
        this.elements = new Object[initialCapacity];
    }
    public void push (Object e) {
        ensureCapacity();
        elements[size++] = e;
    }
    public void Object pop() {
        if (size == 0) throw new EmptyStackException();
        return elements[--size];
    }
    /**
     * Ensure space for at least one more element, roughly
     * doubling capacity each time the array needs to grow.
     */
    private void ensureCapacity() {
        if (elements.length == size) {
            Object[] oldElements = elements;
            Elements = new Object[2 * elements.length + 1];
            System.arrayCopy(oldElement, 0, elements, 0, size);
        }
    }
}
On the face of it the object is fine and there are no problems, but there is a hidden memory leak. This happens in the pop method. As the objects are popped out of the stack they are no longer required in the array, but since there is a reference to these objects in the array the garbage collector does not know that these can be collected. This means that even though the Stack has shrunk in size the memory is not getting released and this can cause problems depending on how the object is used.
The way to fix is to nullify the references that are not required as below
    public void Object pop() {
        if (size == 0) throw new EmptyStackException();
        Object result = elements[size];
        elements[--size] = null;
        return result;
    }
This does not mean that one should nullify every object that is not required. This mechanism should be used only under condition as described above, i.e. in scenarios where the Class is managing its own memory without the knowledge of Garbage Collector.
Cache is another source of such leaks. If object in the cache are no longer required, then references to them should be removed. If the reference to the objects needs to cease based on reference to the object outside the scope of the cache then using a WeakHashMap will automatically remove the object from the Map once the reference to the object outside the cache is removed.
If it is not known as to when the object out of scope but it is desired that it be possible to remove objects based on the oldest object then we can use the LinkedHashMap object. This allows for removeEldestEntry which will remove the earliest entry.

Avoid Finalizers

Finalizers are invoked when the object is Garbage collected. It is not known as to when the Garbage Collection will kick off. Given this one should not depend on the finalzer to free resources. Resources should be freed typically in the finally block. If one depends on finalizer to free resources it maybe too late. Expect the clients of the class to invoke the method for freeing of the resources 

The next post is about the best practices in writing methods which are common to all the classes.

No comments: