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.