Effective Java 3rd edition ch2

Creating and destroying objects

Mohamed Elmaghraby
9 min readNov 13, 2020

Item 1 “Static factory method instead of constructor”

Example of static factory method

public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}

Advantages:

  1. Unlike constructors, they have names

Static factories have names to describe the returned object which is better than having multiple constructors with the same object name and different parameters (choose names carefully).

2. They are not required to create a new object each time they’re invoked

This allows managing objects created by caching them and avoiding creating unnecessary objects (better for Immutable classes), this is called an instance-controlled class. It can improve performance especially if objects are expensive to be created.

3. They can return an object of any subtype of their return type

This can be used to hide class implementation which leads to “interface-based frameworks”.

4. The returned object can vary from call to call as a function of the input parameters

This gives the programmer more flexibility to return an object that best fits the parameters.

Example

The EnumSet class returns RegularEnumSet if items less than 64 and returns JumboEnumSet if items are more.
A future release could add more classes or remove any if proved beneficial.

5. The class of the returned object need not exist when the class containing the method is written

The API of the static factory method can return an interface type whose implementation will be written or generated later. check this

Disadvantages

The main limitation of providing only static factory methods is that classes without public or protected constructors cannot be subclassed, but this encourages using composition instead of inheritance. check this

Item 2 “Consider a builder when faced with many constructor parameters”

Static factories and constructors share a limitation: they do not scale well to large numbers of optional parameters.

Available options:

1. Telescope constructor:

In which you provide a constructor with only the required parameters, another with a single optional parameter, a third with two optional parameters, and so on.

Disadvantage: It keeps the reader wondering what all these parameters mean, what to use and he may mistake the order.

Example

// Telescoping constructor pattern - does not scale well!
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;

public NutritionFacts
(int servingSize, int servings) {
this(servingSize, servings, 0);
}
public NutritionFacts
(int servingSize, int servings, int calories) {
this(servingSize, servings, calories, 0);
}
public NutritionFacts
(int servingSize, int servings, int calories, int fat) {
this(servingSize, servings, calories, fat, 0);
}
}

2. JavaBeans pattern:

In which you call a parameterless constructor to create the object and then call setter methods to set each required parameter and each optional parameter of interest.

Disadvantage: JavaBean may be in an inconsistent state partway through its construction and precludes the possibility of making a class immutable.

Example

// JavaBeans Pattern - allows inconsistency, mandates mutability
public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1; // Required; no default value
private int servings = -1; // Required; no default value
private int calories = 0;
private int fat = 0;
public NutritionFacts() { }
// Setters
public void setServingSize(int val) { servingSize = val; }
public void setServings(int val) { servings = val; }
public void setCalories(int val) { calories = val; }
public void setFat(int val) { fat = val; }
}

Using the class

NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);

3. Builder pattern

Instead of making the desired object directly, the client calls a constructor (or static factory) with all of the required parameters and gets a builder object. Then the client calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the client calls a parameterless build method to generate the object, which is typically immutable.

It combines the safety of the telescoping constructor pattern with the readability of the JavaBeans pattern.

Example:

public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;

public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;

public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }

public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
}
}

The builder’s setter methods return the builder itself so that invocations can be chained, resulting in a fluent API

NutritionFacts cocaCola 
= new NutritionFacts.Builder(240, 8) .calories(100).build();

Item 3 “Enforce the Singleton property with a private constructor or an enum type”

There are two common ways to implement singletons. Both are based on keeping the constructor private and exporting a public static member to provide access to the sole instance.

  • In one approach, the member is a public final field.
// Singleton with public final field
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public void leaveTheBuilding() { ... }
}
  • In the second approach, the member is a public static factory method.
// Singleton with static factory
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE; }
public void leaveTheBuilding() { ... }
}

All calls to Elvis.getInstance return the same object reference, and no other Elvis instance will ever be created The main advantage is it gives you the flexibility to change the class to be non-singleton without changing the API.

To make the singleton class serializable, it is not sufficient to add implements Serializable. You need to make declare all the fields Transient and provide a readResolve method.

private Object readResolve() {
return INSTANCE;
}
  • A third way to implement singleton, declare a single-element enum
public enum Elvis {
INSTANCE;
// other methods
}

This provides serialization machinery for free, but it can't be used if your singleton must extend a superclass.

Item 4 “Enforce non-instantiability with a private constructor”

This may be needed when a class is just a grouping of static methods and static fields. Abstract class doesn’t help here as it still can be inherited and instantiated from the subclasses, also it misleads the user into thinking the class was designed for inheritance.

This is achieved by making the constructor of the class private.

// Noninstantiable utility class
public final class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {}
... // Remainder omitted
}

This also prevents the class to be subclassed due to the final keyword.

Item 5 “Prefer dependency injection to hardwiring resources”

Don’t use a singleton or static utility class to implement a class that depends on one or more underlying resources whose behavior affects that of the class, and don’t have the class create these resources directly as this assumes there is only the local resource and doesn’t allow users to pass their own resources.

Instead, pass the resources or factories to create them into the constructor (or static factory or builder).

// Dependency injection provides flexibility and testability
public class SpellChecker {
private final Lexicon dictionary;
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
}
public boolean isValid(String word) { ... }
public List<String> suggestions(String typo) { ... }
}

Item 6 “Avoid creating unnecessary objects”

It is often appropriate to reuse a single object instead of creating a new functionally equivalent object each time it is needed (especially if the object is Immutable), this can be achieved by using the “static factory method”.

Example

String s = new String("new word")

The above code is too costly if used in a loop, as each time a new object will be created.

Instead use

String s = "new word"

In addition to reusing immutable objects, you can also reuse mutable objects if you know they won’t be modified.

Example

static boolean isNumber(String s) {
return s.matches("[1-9][0-9]*");
}

Each time this method is called a new Pattern instance is created, so it is better to cache it and reuse it.

Instead use

public class Numeric {
private static final Pattern NUMBER
= Pattern.compile("1-9][0-9]*";
static boolean isNumber(String s) {
return s.matches(NUMBER);
}
}

Tip: “Prefer primitives to boxed primitives, and watch out for unintentional autoboxing”

Example:

private static long sum() {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}

Each time the value of the sum changes a new object is created which means that the program constructs about 2^31 unnecessary Long instances. Changing the declaration of the sum from Long to long reduces the runtime significantly.

Conversely, avoiding object creation by maintaining your own object pool is not always the best idea unless the objects in the pool are extremely heavyweight.

Item 7 “Eliminate Obsolete object references ”

When you start using a language with garbage collection your first impression is I don’t have to think about memory management but this isn’t true, there are examples where garbage collectors fail.

Example 1: “implementing a stack as an array”

public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[ — size];
}
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}

The memory leak here exists when the stack grows 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. The fix for this sort of problem is simple: null out references once they become obsolete.

public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[ — size];
elements[size] = null; // Eliminate obsolete reference
return result;
}

Generally speaking, whenever a class manages its own memory, the programmer should be alert for memory leaks.

2- Another common source of memory leaks is caching. Once you put an object reference into a cache, it’s easy to forget that it’s there and leave it in the cache long after it becomes irrelevant.

The common rule is the cache should occasionally be cleaned of entries that have fallen into disuse. This can be done by a background thread (perhaps a ScheduledThreadPoolExecutor) or as a side effect of adding new entries to the cache like The LinkedHashMap class with its removeEldestEntry method.

WeakHashMap class is useful if the desired lifetime of cache entries is relevant exactly so long as there are references to its key. It ensures the cache entries will be removed automatically after they become obsolete.

Item 8 “Avoid finalizers and cleaners”

Finalizers are unpredictable, often dangerous, and generally unnecessary. Cleaners are less dangerous than finalizers but still unpredictable, slow, and generally unnecessary.

It can take arbitrarily long between the time that an object becomes unreachable and the time its finalizer or cleaner runs. This means that you should never do anything time-critical in a finalizer or cleaner.

So what should you do instead of writing a finalizer or cleaner for a class whose objects encapsulate resources that require termination, such as files or threads? Just have your class implement AutoCloseable, and require its clients to invoke the close method on each instance when it is no longer needed, typically using try-with-resources to ensure termination even in the face of exceptions.

So what, if anything, are cleaners and finalizers good for? One usage is to act as a safety net in case the owner of a resource neglects to call its close method. While there’s no guarantee that the cleaner or finalizer will run promptly (or at all), it is better to free the resource late than never if the client fails to do so.

Item 9 “prefer try-with-resource to try-finally”

The Java libraries include many resources that must be closed manually by invoking a close method. Examples include InputStream, OutputStream, and java.sql.Connection.

Historically, a try-finally statement was the best way to guarantee that a resource would be closed properly, even in the face of an exception or return

static String firstLineOfFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}

The code in both the try block and the final block is capable of throwing exceptions. For example, the call to readLine could throw an exception due to a failure in the underlying physical device, and the call to close could then fail for the same reason. Under these circumstances, the second exception completely obliterates the first one.

All of these problems were solved with the try-with-resources statement To be usable with this construct, a resource must implement the AutoCloseable interface, which consists of a single void-returning close method.

static String firstLineOfFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader
(new FileReader(path))) {
return br.readLine();
}
}

If exceptions are thrown by both the readLine call and the (invisible) close, the latter exception is suppressed in favor of the former. In fact, multiple exceptions may be suppressed in order to preserve the exception that you actually want to see. These suppressed exceptions are not merely discarded; they are printed in the stack trace with a notation saying that they were suppressed.

The lesson is clear: Always use try-with-resources in preference to trying finally when working with resources that must be closed. The resulting code is shorter and clearer, and the exceptions that it generates are more useful.

Order the effective Java 3rd edition book for the author “Joshua Bloch” from here

--

--