Creating and Destroying Objects
Consider static factory methods instead of constructors
- flexible way of object instantiation 
Pro
- static factories have names, unlike constructors 
- not required to create a new object on each invocation 
- called instance controlled 
- enable singleton and non-instantiability guarantees 
- allows immutable value class to guarantee no two instances exist 
- forms the basis of Flyweight Pattern 
- Enum types provide this guarantee 
- can return an object of any subtype of their return type 
- lends itself to interface-based frameworks 
- allow the class of the returned object to vary from call to call as function of input params 
- do not require the class of returned object to exist when the class containing the method is written - form the basis of service provider frameworks ie jdbc 
 
Cons
- classes without public/protected constructors cannot be subclassed 
- encourages composition (which is good) 
- hard to find in documentation 
- they scale poorly with the increase of (optional) params 
Naming
- from() 
- of() 
- valueOf() 
- instance() or getInstance() 
- getType() 
- newType() 
- type() 
Consider a builder when faced with many constructor params
- Handle increase in params, esp optional ones - Solutions: - telescoping constructor - scales poorly 
- JavaBeans pattern - need setters - causes inconsistency 
- no immutablitiy 
 
 
 
- Builder solves these 
Pro
- static member class 
- client code is easy to write - fluent style 
 
- incorporate validity checks - can throw IllegalStateException 
 
- Can construct any subclass - generic builder with recursive type parameters 
- abstract self() simulates self-type which, combined with covariant return typing, obviates need for casting 
 
- flexible 
cons
- cost of creating a builder 
- verbose 
Enforce the singleton property when a private constructor or enum type
how
- with public final field 
- with static factory 
- with a single-element enum (preferred) - well-defended against reflection 
- prevents serialization issues 
 
con
- making a class a singleton can make it difficult to test 
Enforce non-instantiability with a private constructor
- class that is simply a grouping of static methods and static fields 
- uses - group related methods on primitive values or arrays 
- group static methods, including factories - default methods are also available (providing we own the interface) 
 
- group methods on a final class, since we can’t put them in a subclass 
 
How
- make such classes non-instantiable - provide an explanatory comment 
- throw an AssertionError from constructor instead of empty one, to guard against accidental constructions from within the class 
- as a side-effect, this class is now effectively final - the class cannot be subclassed as there are no available constructors 
- it is good to document this a make the class itself final 
 
 
Prefer dependency injection to hard-wiring resources
- do not use static utility methods or singletons to handle creations of class’ resources 
- favour dependency injection by supplying the required resource parametrically - testable 
- flexible (esp. with Factory Method pattern - Supplier is perfectly suited for representing factories 
- methods that take this interface should typically constrain the factory’s type parameter with a bounded wildcard type - the client should be able to pass in a factory that requires any subtype of a specified type 
 
 
 
- Can use frameworks to do this 
Avoid creating unnecessary objects
- avoided by using static factory methods 
- some object creations are much more expensive than others - it may be advisable to cache such objects 
- ie regex patterns, database connections 
 
- immutable objects can trivially be reused 
- Use Adapters aka views - adapter is an object delegating to a backing object, providing an alternative interface 
- has not state beyond the backing object thus provides a view of it 
- example: keySet() in Map interface 
 
- autoboxing can often subtly create unnecessary objects 
- almost never create own object pools - JVM gc will almost always outperform such pools 
- exception to this: very expensive objects - example: database connection objects 
 
 
- counterpoint to this is defencive copying 
Eliminate obsolete object references
- common sources of leaks - a resizing-array stack that doesn’t null out its references on pop() 
- classes that manage their own memory 
- caches - can be mitigated with WeakHashMap 
- sophisticated caches might need to use java.lang.ref directly 
 
- listeners and other callbacks - APIs that register callbacks but don’t deregister them explicitly 
- can be mitigated with WeakHashMap 
 
 
- anticipate such problems before they occur as they can be very costly to fix 
Avoid finalizers and cleaners
- finalizers and cleaners are used to reclaim non-memory resources - example: input/output streams, files, etc. 
- Different to deconstructors 
 
- finalizers are unpredictable, dangerous and generally unnecessary 
- cleaners are less dangerous than finalizers but still slow, unpredicatble and generally unnecessary 
Cons
- spec makes no guarantee when they’ll be executed - their execution is a function of GC algorithm, thus JVM implementation 
- never do anything time-critical in a finalizer or cleaner 
- providing a finalizer may arbitrarily delay reclamation of class’ instances 
- cleaners are a bit better but still run under the control of GC so still the same applies 
- any existing methods that claim to trigger finalization are decade-old traps - examples: System.runFinalizerOnExit or Runtim.runFinalizerOnExit 
 
 
- uncaught exception thrown during finalization is ignored until finalization of that object terminates - object is potentially left in corrupted state 
- normally, uncaught exception terminates the executing thread and dumps stacktrace but not if it occurs in finalizer 
- cleaners do not suffer from this problem 
 
- there is a severe performance GC penalty for using finalizers and cleaners - finalizers: ~50x slower reclamation 
- cleaners: ~5x slower reclamation, equal to finalizers if they’re used to clean all instance of the class 
 
- finalizers open up classes to finalizer attacks - if an exception is thrown during finalization, the finalizer leaves the class unreclaimed 
- attackers can exploit this and run code that shouldnt’ve existed 
- to protect non-final classes against it - write a final finalize() that does nothing 
 
when
- except as a safety net or to terminate non-critical native resources 
Alternatives
- instead of using finalizers or cleaners simply use AutoCloseable - require clients to invoke close() whenever instance is not required 
 
Prefer try-with-resources to try-finally
- Java libraries include many resources that must be closed manually by invoking close() 
- closing objects is often overlooked by clients 
- try-finally was the best way to guarantee a resource would be closed properly, even when facing exception or return - while it doesn’t look bad for a single resource, it doesn’t scale well with the increase of resources required to be closed 
- nested finally block complicate debugging 
 
- try-with-resources suffers none of this issues - shorter, more readable than try-finally 
- provides far better diagnostics 
- no exceptions are suppressed 
 
Last updated
Was this helpful?