Effective Java 2nd edition

8382 ワード

Item 3: Enforce the singleton property with a private constructor or an enum type
 
While this approach has yet to be widely adopted , a single-element enum type is the best way to implement a singleton.
 
have yet to is a phrasal verb, like Certain questions have yet to be clarified.
 
have yet to do sth. = have not yet done sth.
 
interface HasAge {
    public int getAge();
}

public enum Elvis implements HasAge {
    INSTANCE;
    private int age;

    @Override
    public int getAge() {
        return age;
    }

    public static void main(String[] args) {
        System.out.println(Elvis.INSTANCE.getAge());
    }
}

 
like this one, static methods in traditional singleton implementation cannot achieve this, as it's non-static method.
 
and why doesn't the enum singleton have the deserialization problem? here's probably the anwser:
 
Enum constants are deserialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not transmitted.
http://electrotek.wordpress.com/2008/08/06/singleton-in-java-the-proper-way/
 
Item 77: For instance control, prefer enum types to readResolve
 
This class restricts access to its constructor to ensure that only a single instance is ever created
As noted in Item 3, this class would no longer be a singleton if the words “implements Serializable” were added to its declaration.
 
The readResolve feature allows you to substitute another instance for the one created by readObject [Serialization, 3.7].If the class of an object being deserialized defines a readResolve method with the proper declaration, this method is invoked on the newly created object after it is deserialized. The object reference returned by this method is then returned in place of the newly created object. In most uses of this feature, no reference to the newly created object is retained, so it immediately becomes eligible for garbage collection.
 
Item 5: Avoid creating unnecessary objects
 
Reuse can be both faster and more stylish. An object can always be reused if it is immutable.
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;
    }
}

 you see, it uses static instances instead of local variables.
 
prefer primitives to boxed primitives, and watch out for unintentional autoboxing.
 
This item should not be misconstrued to imply that object creation is expensive and should be avoided. On the contrary, the creation and reclamation of small objects whose constructors do little explicit work is cheap, especially on modern JVM implementations. Creating additional objects to enhance the clarity, simplicity, or power of a program is generally a good thing.
 
Item 6: Eliminate obsolete object references
You can think of direct references as strong references that require no extra coding to create or access the object. The remaining three types of references are subclasses of the     Reference class found in the java.lang.ref package. Soft references are provided by the SoftReference class, weak references by the WeakReference class, and phantom references by PhantomReference.     Soft references act like a data cache. When system memory is low, the garbage collector can arbitrarily free an object whose only reference is a soft reference. In other words, if there are no strong references to an object, that object is a candidate for release. The garbage collector is required to release any soft references before throwing an OutOfMemoryException.     Weak references are weaker than soft references. If the only references to an object are weak references, the garbage collector can reclaim the memory used by an object at any time. There is no requirement for a low memory situation. Typically, memory used by the object is reclaimed in the next pass of the garbage collector.     Phantom references relate to cleanup tasks. They offer a notification immediately before the garbage collector performs the finalization process and frees an object. Consider it a way to do cleanup tasks within an object.
 
import java.lang.ref.WeakReference;

public class WeakTest {
    public static void main(String[] args) {
        String s = new String("Hello");
        WeakReference<String> wr = new WeakReference<String>(s);
        s = null;                                                                    
        System.gc();
        System.out.println(wr.get());
    }
}

s is strong reference, and wr is weak reference, after gc, it prints null, it shows that the object with only the weak reference would be taken back.
 
Item 7: Avoid finalizers
In Java, the garbage collector reclaims the storage associated with an object when it becomesunreachable , requiring no special effort on the part of the programmer.
 
Item 70: Document thread safety
 
Documenting a conditionally thread-safe class requires care. You must indicate which invocation sequences require external synchronization, and which lock (or in rare cases, which locks) must be acquired to execute these sequences. Typically it is the lock on the instance itself, but there are exceptions. If an object represents a view on some other object, the client generally must synchronize on the backing object, so as to prevent its direct modification. For example, the documentation for Collections.synchronizedMap says this: It is imperative that the user manually synchronize on the returned map when iterating over any of its collection views:
Map m = Collections.synchronizedMap(new HashMap());

...

Set s = m.keySet(); // Needn't be in synchronized block

...

synchronized(m) { // Synchronizing on m, not s!

    Iterator i = s.iterator(); // Must be in synchronized block

    while (i.hasNext()) foo(i.next());

}
 
Failure to follow this advice may result in non-deterministic behavior.
 
now the question is why needn't be in synchronized block?
 
answer:
Without Collections.synchronizedMap() (assuming there is no external synchronization) the behaviour will be non-deterministic. 1. The use of the above method ensures that any thread trying to execute a method of Map will be forced to aquire lock on the Map. 2. But the above method does NOT make access through ITERATORS synchronized. So if we are accessing through iterators, such access must be separately synchronized on the Map. Consider what may happen if we do not use the synchronizedMap() method (and also do not externally synchronize). Then Thread1 and Thread2 may concurrently execute the above code. Thread1 may call keySet() even while Thread2 is concurrently modifying the Map maybe in foo(i.next()). Clearly the results will be unpredicatable.
http://www.coderanch.com/t/231408/threads/java/Synchronized-method-blocks