Item 4: Enforce noninstantiability with a private constructor
有些类需要防止用户实例化一个类,比如说java.lang.Math 和java.util.Arrays,Attempting to enforce noninstantiability by making a class abstract does not work.A class can be made noninstantiable by including a private constructor://Noninstantiable utility class public class UtilityClass { // Suppress default constructor for noninstantiability private UtilityClass() { throw new AssertionError(); } ... // Remainder omitted }
Item 5: Avoid creating unnecessary objects
String s = new String("stringette"); // DON'T DO THIS!
String s = "stringette"; //DO THIS 每一次运行该代码,JVM都保证只有一个"stringette"实例
1.public class Person { private final Date birthDate; // Other fields, methods, and constructor omitted ITEM 5: AVOID CREATING // UNNECESSARY OBJECTS 21 // DON'T DO THIS! public boolean isBabyBoomer() { // Unnecessary allocation of expensive object Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); Date boomStart = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); Date boomEnd = gmtCal.getTime(); return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0; } }
2.class Person { private final Date birthDate; // Other fields, methods, and constructor omitted /** * The starting and ending dates of the baby boom. */ private static final Date BOOM_START; private static final Date BOOM_END; static { Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); BOOM_START = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); BOOM_END = gmtCal.getTime(); } public boolean isBabyBoomer() { return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0; } }
On my machine, the original version takes 32,000 ms for 10 million invocations, while the improved version takes 130 ms, which is about 250 times faster.
// Hideously slow program! Can you spot the object creation? public static void main(String[] args) { Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); }
Changing the declaration of sum from Long to long reduces the runtime from 43 seconds to 6.8 seconds on my machine. The lesson is clear: prefer primitives to boxed primitives, and watch out for unintentional autoboxing.
Item 6: Eliminate obsolete object references
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]; } /** * Ensure space for at least one more element, roughly doubling the capacity * each time the array needs to grow. */ private void ensureCapacity() { if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } }
每次执行Stack的pop操作,Stack的大小只是在逻辑上减少了,而Object[]中对pop出来的元素的引用依然存在,所以GC不能将其回收,这样的引用被称作obsolete references,这会导致内存泄露。这样做能够避免上述情况:
public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result; } 但是,Joshua提醒:Nulling out object references should be the exception rather than the norm.Generally speaking, whenever a class manages its own memory, the programmer should be alert for memory leaks.Another common source of memory leaks is caches.A third common source of memory leaks is listeners and other callbacks.
Item 7: Avoid finalizers
1. Finalizers are unpredictable, often dangerous, and generally unnecessary.
2. Never depend on a finalizer to update critical persistent state
3. There is a severe performance penalty for using finalizers.
4. Explicit termination methods are typically used in combination with the try-finally construct to ensure termination.