Effective Java Practices: Builder Pattern, Object Creation, and Performance Optimizations
This article presents a collection of Java best‑practice guidelines—including using the Builder pattern for many constructor arguments, privatizing utility class constructors, minimizing object creation, avoiding finalizers, applying the Law of Demeter, preferring enums, and careful use of var‑args—to improve code readability, memory usage, and runtime performance.
Below is a concise set of practical Java tips aimed at improving code quality, performance, and maintainability.
1. Too many constructor parameters – use the Builder pattern
When a class has five or more parameters, or when parameters are expected to grow, introduce a Builder to assemble the object step‑by‑step.
public class Computer {
protected String mBoard;
protected String mDisplay;
protected String mOs;
private Computer(Builder builder) {
this.mOs = builder.mOs;
this.mBoard = builder.mBoard;
this.mDisplay = builder.mDisplay;
}
@Override
public String toString() {
return "Computer{" + "mBoard='" + mBoard + '\'' + ", mDisplay='" + mDisplay + '\'' + ", mOs='" + mOs + '\'' + '}';
}
static class Builder {
protected String mBoard;
protected String mDisplay;
protected String mOs;
public Builder setmOs(String mOs) { this.mOs = mOs; return this; }
public Builder setmBoard(String mBoard) { this.mBoard = mBoard; return this; }
public Builder setmDisplay(String mDisplay) { this.mDisplay = mDisplay; return this; }
public Computer build() { return new Computer(this); }
}
}Usage example:
public static void main(String[] args) {
Computer macbook = new Computer.Builder()
.setmBoard("board")
.setmDisplay("sowhat")
.setmOs("Mac")
.build();
System.out.println(macbook);
}2. Privatize constructors of utility classes
Utility classes such as java.util.Arrays should not be instantiated; make their constructors private.
public class Arrays {
private static final int MIN_ARRAY_SORT_GRAN = 8192;
private static final int INSERTIONSORT_THRESHOLD = 7;
private Arrays() { }
}3. Avoid creating unnecessary objects
Prefer primitive types over boxed types, reuse static fields, employ connection pools, and keep large objects short‑lived to reduce GC pressure.
// Example showing the cost of boxing Long in a tight loop
public class Sum {
public static void main(String[] args) {
long start = System.currentTimeMillis();
Long sum = 0L; // boxed object
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum = sum + i; // creates billions of Long objects
}
System.out.println("spend time:" + (System.currentTimeMillis() - start) + "ms");
}
}Replacing the boxed Long with a primitive long reduces execution time dramatically.
4. Avoid using finalizers
Finalizers are unpredictable and may never run; rely on explicit resource management (try‑with‑resources) instead of finalize() or System.gc().
5. Minimize class and member visibility (Law of Demeter)
Keep fields private and expose only necessary behavior to reduce coupling.
6. Minimize mutability
Declare fields final whenever possible to simplify thread‑safety.
7. Prefer composition over inheritance
Use wrapper classes rather than extending across package boundaries to avoid fragile hierarchies.
8. Prefer interfaces to abstract classes
Java allows multiple interface implementations, supporting the Open/Closed principle; use skeletal abstract classes only when many implementations share common code.
9. Use var‑args cautiously
Var‑args create an array on each call; for performance‑critical code, provide overloaded methods for the most common argument counts.
10. Return empty collections instead of null
Returning Collections.EMPTY_LIST or an empty array avoids unnecessary null checks.
11. Prefer standard exceptions
Using familiar JDK exceptions improves readability and reduces class‑loading overhead.
12. Replace magic int constants with enums
Enums provide type safety and expressive code.
13. Minimize the scope of local variables
Declare variables close to their first use and keep methods small to aid GC and improve readability.
14. Use BigDecimal for precise decimal arithmetic
Floating‑point types introduce rounding errors; BigDecimal should be used for financial calculations.
15. Prefer StringBuilder / StringBuffer for mutable strings
String is immutable; for frequent modifications use the mutable builders.
16. Close resources separately
Closing resources in separate try blocks prevents one failure from masking another.
17. Efficient primitive‑to‑String conversion
Use Integer.toString() (fastest), then String.valueOf(), and avoid concatenation with + "" (slowest).
18. Null out references after use
Explicitly setting unused references to null helps the GC reclaim memory sooner.
19. Constant‑first comparisons
Write if (1 == i) to avoid accidental assignment errors.
20. Use "literal".equals(variable) to avoid NPE
Placing the literal first guarantees a non‑null call.
21. Prefer synchronized blocks over synchronized methods
Lock only the critical section to reduce contention.
22. Keep methods small
Small methods are more likely to be inlined by the JIT, improving performance.
23. Write meaningful comments
Even well‑written code benefits from clear class and method documentation.
References: Alibaba Java Coding Guidelines, Builder Pattern, finalize & GC, Deep Dive into String.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
