Creating and Destroying Objects

Item1: Use static factory methods instead of constructors

Pros

Static factory method has many advantages, such as the method can have its own name to indicate its usage, it is not necessary to create and return a new object each time when called like constructors do, and the objects returned are flexible, because it can be any subclass of the class itself, or it can vary from input to input.

Cons

Classes with only static factory methods can not be subclassed without public or protected constructors, and it may be difficulty for other developer to find out these static factory methods.

Tips

The static factory methods can be named by following below rules:

  • from
  • of
  • valuesOf
  • getInstance
  • type

These are just my personal preference.

Item2: Use builders to replace constructors with many parameters

Pros

Builders can make code easy to read and understand, because constructos with too many parameters would make things confusing and hard to use (when you have some optional parameters, you may provide so many constructors to cover all the situations). Also it is friendly to class hierarchies.

Tips

In some Java frameworks, use annotation @Builder to make the object support the builder method.

Item3: Use private constructors or an enum type to enforce the singleton property

By using private constructors, it can be guaranteed that the constructor would not be called from outside of the class, and then we can provide a static field to initialize with the private constructor, and we can make it private or public: If private, we need a static factory method to get the instance; If public, we can get the instance directly.

Pros

For public field, the API makes it singleton definitely.

For static factory method, it is flexible.

Enum type

By building an enum class and always returning the enum instance, it can also be used to guarantee a single object.

This is the best way to implement a singleton, which it can not be applied when extending a superclass unless it is Enum.

Item4: Protect noninstantiability with a private constructor

Utility classes should not be instantiated, so that we can use a private constructor to prevent others from instantiating it. We can also add an exception thrown in the private constructor to prevent it from being called in the class.

Pros

A private constructor will replace the default public constructor of the class, so that it would be safe to keep the class from being instainating.

Cons

The class with a private constructor could not be subclassed.

Item5: Use dependency injection

Static utility classes and singletons should not be applied to classes whose behavior is parameterized by an underlying resource. We should also not have classes to create resource in them, but pass resources or factories to the constructors.

Spring, as a dependency injection framework, can help us do this.

Item6: Avoid creating unnecessary objects

We may create unnecessary objects accidentally, like String s = new String("xxx");. We should use String s = "xxx" instead.

Also, we can use static factory rather than constructors, like Boolean.valueOf(String), instead of Boolean(String).

Autoboxing is another thing that is worth paying attention to. We should avoid this: Long i = 100; long j = 100; Long k = i+j;

Item7: Eliminate obsolete object references

Obsolete object references would lead to memory leak, like in a growing and shrinking stack. To avoid this, make the element popped null manually.

// Before
public Object pop() {
  return element[--size];
}

// After
public Object pop() {
  Object result = element[--size];
  element[size] = null;
  return result;
}

Another source of memory leaks is caches. WeakHashMap and LinkedHashMap can be helpful to solve this.

Also, listeners and other callbacks can be another source of memory leaks. We can store them as keys in a WeakHashMap to solve this.

Item8: Avoid finalizers and cleaners

Java is not like C++, programmers do not have to manage the memory manually. Besides, finalizers and cleaners are dangerous, thought the latter one is better than the former one. JVM would take care of GC, and at the most time it works just perfectly.

Item9: try-with-resource is better than try-finally

When we need to deal with multi resources, try-finally method would perform badly, because we need to apply try-resource to every resource separately.

Use try-with-resource instead:

try(InputStream in = new FileInputStream(src);
    OutputStream out = new FileOutputStream(dst)) {
  // do something
} catch(Exception e) {
  // do something
}

Another benefit is that it would not suppress exceptions, so that it could generate more useful exceptions.