Skip to main content

Static Factories and Builders

Source: Effective Java, 3rd Edition — Chapter 2 by Joshua Bloch (Items 1–5)

This chapter is about creating and destroying objects: when to create them, when not to, and how to hand off the dependencies they need. Items 1–5: static factories, builders, singletons, noninstantiable utilities, and dependency injection.

Item 1: Prefer static factory methods​

A static factory method is a public static method that returns an instance. Not the Gang-of-Four “Factory Method” pattern — just a named static that hands you an object.

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

Advantages​

  1. Names. BigInteger.probablePrime(...) beats a three-arg constructor nobody can decode. Same signature twice? Give each factory a clear name instead of swapping parameter order (a trap).
  2. Need not create a new object. Immutable types can cache / reuse (Boolean.TRUE). Instance-controlled classes: singleton, noninstantiable, or “a.equals(b) iff a == b” (Flyweight). Enums do this for free.
  3. Return any subtype of the declared type. Keep implementation classes package-private; clients code to the interface (Collections.unmodifiableList). Before Java 8, factories lived in a companion Types class; now many sit on the interface (Java 9: private static methods allowed; static fields on interfaces are still public).
  4. Return type can depend on the arguments (and change across releases). EnumSet.of(...) picks RegularEnumSet vs JumboEnumSet by enum size — clients never see those names.
  5. Returned class need not exist yet — service-provider frameworks (JDBC: Connection, DriverManager.registerDriver / getConnection, Driver). Prefer ServiceLoader today unless you are stuck on legacy APIs.

Costs​

  • No public/protected constructor → cannot subclass (often good: push composition, Item 18; required for many immutables).
  • Harder to discover in Javadoc than constructors. Document them and use common names:
NameMeaning
fromconvert one value
ofaggregate many
valueOfverbose from/of
getInstance / instancedescribed by params, not “same value”
newInstance / createnew object each call
getType / newType / typefactory lives in another class

Constructors still have a place — just do not reach for a public constructor on reflex.

Quiz

Static factories

1 / 2

Boolean.valueOf(true) called twice

Pick an answer to see if you are right.

Item 2: Prefer a builder for many parameters​

Optional fields explode. Three bad/good options:

Telescoping constructors​

NutritionFacts(size, servings), then add calories, fat, … — does not scale. Call sites pass dummy zeros; identical ints get swapped silently.

JavaBeans​

Empty constructor + setters. Readable, but the object is mutable, can be half-built, and hard to keep consistent or thread-safe. “Freeze” APIs are awkward.

Builder​

Required args in Builder(...); optional chainable setters return this; build() produces an immutable instance. Fluent and self-documenting:

NutritionFacts cola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35).carbohydrate(27).build();

Validate early in builder setters; multi-field invariants in the private constructor after copying from the builder. Hierarchies: abstract Pizza.Builder<T extends Builder<T>> + self() (simulated self-type) and covariant build() in subclasses (NyPizza, Calzone).

Cost: an extra object; more code than a short telescoping list. Worth it around four or more parameters, especially optional or same-typed. Starting with a builder beats shipping telescoping APIs you later regret.

Item 3: Enforce a singleton​

Exactly one instance. Harder to mock unless the type is an interface.

  1. public static final field + private constructor — clearest API, simplest.
  2. getInstance() static factory — can later change policy (per-thread, etc.); works as a method reference Elvis::getInstance.
  3. Single-element enum — preferred: concise, serialization-safe, reflection-resistant. Cannot extend another class (can implement interfaces).

Serializable field/factory singletons need transient fields + readResolve() returning INSTANCE, or deserialization creates clones.

Item 4: Noninstantiable utility classes​

Math, Arrays, Collections: static groups only. Making the class abstract fails — someone subclasses and constructs. Suppress the default constructor:

public class UtilityClass {
private UtilityClass() {
throw new AssertionError();
}
}

Side effect: no subclasses (no accessible super constructor).

Quiz

Noninstantiable utility classes

1 / 2

A class like Math or Collections that only holds static methods

Pick an answer to see if you are right.

Item 5: Prefer dependency injection​

Do not hard-wire a Lexicon inside a static utility or singleton SpellChecker. Languages, test dictionaries, and concurrency all break that assumption.

Inject the resource (or a Supplier<? extends Tile> factory) into the constructor / static factory / builder:

public class SpellChecker {
private final Lexicon dictionary;
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
}
}

Simple, testable, immutable-friendly. Large graphs → Guice / Spring / Dagger — APIs designed for manual DI adapt cleanly.

Quiz

Dependency injection

1 / 1

SpellChecker that must work with many dictionaries

Pick an answer to see if you are right.

Chapter 2 so far​

ItemMove
1Named static factories; cache; hide subtypes
2Builder when optional/same-typed params pile up
3Singleton via field, factory, or enum
4Private constructor (+ AssertionError) for utilities
5Inject resources; do not hard-wire them

Next items pick up cleanup, avoid unnecessary objects, and more creation pitfalls.