-----------------------------------------------------------------------------
Item 1: Consider providing static factory methods instead of constructors
One advantage of static factory methods is that, unlike constructors, they have names.
A second advantage of static factory methods is that, unlike constructors, they are not required to create a new object each time they're invoked.
A third advantage of static factory methods is that, unlike constructors, they can return an object of any subtype of their return type.
public static Foo getInstance(String key)
{
initMapIfNecessary();
Class c = (Class) implementations.get(key);
if (c == null) return new DefaultFoo();
(Foo) c.newInstance();
......
The main disadvantage of static factory methods is that classes without public or protected constructors cannot be subclassed.
A second disadvantage of static factory methods is that they are not readily distinguishable from other static methods.
Item 2: Enforce the singleton property with a private constructor
//Singleton with final field
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {... }
...
The main advantage of the first approach is that the declarations of the members comprising the class make it clear that the class is a singleton: the public static field is final, so the field will always contain the same object reference.
//Singleton with static factory
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() {
return INSTANCE;
}
...
The main advantage of the second approach is that it gives you the flexibility to change your mind about whether the class should be a singleton without changing the API.
To make a singleton class serializable, it is not sufficient merely to add implements Serializable to its declaration. To maintain the singleton guarantee, you must also provide a readResolve method. Otherwise, each deserialization of a serialized instance will result in the creation of a new instance
//readResolve method to preserve singleton property
private Object readResolve() throws ObjectStreamException {
//Return the one true Elvis and let the garbage collector take care of the Elvis impersonator.
return INSTANCE; }
Item 3: Enforce noninstantiability with a private constructor
A class can be made noninstantiable by including a single explicit private constructor:
//Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
//This constructor will never be invoked
}
Item 4: Avoid creating duplicate objects
An object can always be reused if it is immutable
String s = new String("silly"); // DON'T DO THIS!
String s = "No longer silly";
creates Calendar, TimeZone, and Date instances only once, when it is initialized, instead of creating them every time isBabyBoomer is invoked.
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)
Item 5: Eliminate obsolete object references
return elements[ --size ]; //wrong approach, will never be deference d, causes memory leak
Object result = elements[ --size ]; elements[size] = null; // Eliminate obsolete reference
return result;
Item 6: Avoid finalizers
There is no guarantee that finalizers will be executed promptly
Don't be seduced by the methods System.gc and System.runFinalization. They may increase the odds of finalizers getting executed, but they don't guarantee it. The only methods that claim to guarantee finalization are System.runFinalizersOnExit and its evil twin, Runtime.runFinalizersOnExit. These methods are fatally flawed and have been deprecated.
Never depend on a finalizer to update critical persistent state. For example, depending on a finalizer to release a persistent lock on a shared resource such as a database
To reclaim other nonmemory resources use try-finally block is generally used for this purpose.
-------Methods-Common-to-All-Objects-------
----------------------------------------------------------------------------
Item 7: Obey the general contract when overriding equals
Each instance of the class is inherently unique.
You don't care whether the class provides a “logical equality” test.
public boolean equals(Object o) {
throw new UnsupportedOperationException();
}
When a class has a notion of logical equality that differs from mere object identity, and a superclass has not already overridden equals to implement the desired behavior. This is generally the case for value classes, such as Integer or Date. A programmer who compares references to value objects using the equals method expects to find out whether they are logically equivalent, not whether they refer to the same object.
public boolean equals(Object o) {
if (!(o instanceof ColorPoint)) return false;
ColorPoint cp = (ColorPoint)o;
return cp.point.equals(point) && cp.color.equals(color);
}
Item 8: Always override hashCode when you override equals
Equal objects must have equal hash codes. Two distinct instances may be logically equal according to the class's equals method, but to the Object class's hashCode method, they're just two objects with nothing much in common. Therefore object's hashCode method returns two seemingly random numbers instead of two equal numbers as required by the contract.
public int hashCode() {
//for class Phone Number
int result = 17;
result = 37*result + areaCode;
result = 37*result + exchange;
result = 37*result + extension;
return result; }
Note: if two objects are equal according to the equals() method, they must have the same hashCode() value (although the reverse is not generally true).
Because on some architectures the address space is larger than the range of values for int, it is possible that two distinct objects could have the same hashCode(). If you override hashCode(), you can still use the System.identityHashCode() method to access this default value.
By defining equals() and hashCode() consistently, you can improve the usability of your classes as keys in hash-based collections.
Item 9: Always override toString
public String toString() { ... }
Item 10: Override clone judiciously
If a class implements Cloneable interface, Object's clone method returns a field-by-field copy of the object; otherwise it throws CloneNotSupportedException.
//Clone method to guarantee that instances cannot be cloned
public final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException(); }
All classes that implement Cloneable should override clone with a public method.This public method should first call super.clone and then fix any fields that need fixing
A fine approach to object copying is to provide a copy constructor.
A copy constructor is simply a constructor that takes a single argument whose type is the class containing the constructor, for example,
public Galaxy(Galaxy aGalaxy) {
this(aGalaxy.getMass(), aGalaxy.getName());
}
A minor variant is to provide a static factory in place of a constructor:
public static Galaxy newInstance(Galaxy aGalaxy) {
return new Galaxy(aGalaxy.getMass(), aGalaxy.getName());
}
When cloned original and copy are references to same object. (bit wise copy)
Any change to either variable effect the other.
Day bday = new Day(1975,11,11);
Day d = (Day) bday.clone();
d.advance(100);
Suppose you have a LinkedList l, and you want to copy it as an ArrayList. The clone method does not offer this functionality, but it's easy with a copy constructor: new ArrayList(l).
A deep copy occurs when an object is copied along with the objects to which it refers.
If a shallow copy is performed on obj1, then it is copied but its contained objects are not, they still refer to same contained objects.
Note: The default clone() method, inherited from Object, makes a shallow copy of the object. To achieve a deep copy, extra logic must be added that explicitly calls all contained objects' clone() methods, which in turn call their contained objects' clone() methods, and so on.
Item 11: Consider implementing Comparable
By implementing java.lang.Comparable interface, a class indicates that its instances have a natural ordering. Sorting an array of objects that implement Comparable is as simple as this:
Arrays.sort(a);
It is similarly easy to search, compute extreme values, and maintain automatically sorted collections of Comparable objects.
--------Classes-And-Interfaces---------
---------------------------------------------------------------
Item 12: Minimize the accessibility of classes and members
A well-designed module hides all of its implementation details, cleanly separating its API from its implementation. Modules then communicate with one another only through their APIs and are oblivious to each others' inner workings. This concept, known as information hiding or encapsulation
--For top-level (non-nested) classes and interfaces, there are only two possible access levels: package-private and public.
By making it package-private, you makeit part of the package's implementation rather than its exported API, and you can modify it, replace it, or eliminate it in a subsequent release without fear of harming existing clients. If you make it public, you are obligated to support it forever to maintain compatibility.
For members (fields, methods, nested classes, and nested interfaces) there are four possible
access levels, listed here in order of increasing accessibility:
- private— The member is accessible only inside the top-level class where it is declared.
- package-private— The member is accessible from any class in the package where it is declared. Technically known as default access, this is the access level you get if no access modifier is specified.
- protected— The member is accessible from subclasses of the class where it is declared (subject to a few restrictions [JLS, 6.6.2]) and from any class in the package where it is declared.
- public— The member is accessible from anywhere.
If a method overrides a superclass method, it is not permitted to have a lower access level in the subclass than it does in the superclass
A simple consequence is that classes with public mutable fields are not thread-safe.
Note that a nonzero-length array is always mutable, so it is nearly always wrong to have public static final array field. Even if array is immutable its elements can be added or removed.
//Potential security hole!
public static final Type[] VALUES = { ... };
The public array should be replaced by a private array and a public immutable list:
private static final Type[] PRIVATE_VALUES = { ... };
public static final List VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
Item 13: Favor immutability
An immutable class is simply a class whose instances cannot be modified. All of the information contained in each instance is provided when it is created and is fixed for the lifetime of the object. The Java platform libraries contain many immutable classes, including String, the primitive wrapper classes, and BigInteger and BigDecimal. There are many good reasons for this: Immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.
To make a class immutable, follow these five rules:
- Don't provide any methods that modify the object (known as mutators).
- Ensure that no methods may be overridden.
- Make all fields final.
- Make all fields private: public final fields can contain primitive values or references to immutable objects
- Ensure exclusive access to any mutable components.
Methods of immutable objects returns new instance of object say
public Complex add(Complex c) { return new Complex(re + c.re, im + c.im); }
Immutable objects are inherently thread-safe; they require no synchronization.
The only real disadvantage of immutable classes is that they require a separate object for each distinct value.
the String class, whose mutable companion is StringBuffer.
The list of rules for immutable classes at the beginning of this item says that no methods may modify the object and that all fields must be final.
constructors should create fully initialized objects with all of their invariants established
Item 14: Favor composition over inheritance
Inheritance breaks encapsulation. In other words, a subclass depends on the implementation details of its superclass for its proper function. The superclass's implementation may change from release to release, and if it does, the subclass may break, even though its code has not been touched.
Instead of extending an existing class, give your new class a private field that references an instance of the existing class. This design is called composition because the existing class becomes a component of the new one. Each instance method in the new class invokes the corresponding method on the contained instance of the existing class and returns the results. This is known as forwarding, and the methods in the new class are known as forwarding methods.
Wrapper class - uses composition in place of inheritance
Item 15: Design and document for inheritance or else prohibit it
Constructors must not invoke overridable methods, directly or indirectly.
The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, then the method will not behave as expected.
Item 16: Prefer interfaces to abstract classes
The most obvious difference between the two mechanisms is that abstract classes are permitted to contain implementations for some methods while interfaces are not. A more important difference is that to implement the type defined by an abstract class, a class must be a subclass of the abstract class.
Because Java permits only single inheritance, this restriction on abstract classes severely constrains their use as type definitions.
Interfaces allow the construction of nonhierarchical type frameworks.
public interface Singer {
AudioClip Sing(Song s);
}
public interface Songwriter {
Song compose(boolean hit);
}
public interface SingerSongwriter extends Singer, Songwriter {
AudioClip strum();
void actSensitive();
}
Item 17: Use interfaces only to define types
The constant interface pattern is a poor use of interfaces. That a class uses some constants internally is an implementation detail. Implementing a constant interface causes this implementation detail to leak into the class's exported API.
You should export the constants with a noninstantiable utility class
Interfaces should be used only to define types.
// Constant interface pattern - do not use!
public interface PhysicalConstants {
static final double AVOGADROS_NUMBER = 6.02214199e23;
static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
static final double ELECTRON_MASS = 9.10938188e-31;
}
// Constant utility class
public class PhysicalConstants {
private PhysicalConstants() { } // Prevents instantiation
public static final double AVOGADROS_NUMBER = 6.02214199e23;
public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
public static final double ELECTRON_MASS = 9.10938188e-31;
}
Interfaces should be used only to define types. They should not be used to export constants.
Item 18: Favor static member classes over nonstatic
There are four kinds of nested classes: static member classes, nonstatic member classes, anonymous classes, and local classes.
All but the first kind are known as inner classes.
A static member class is a static member of its enclosing class and obeys the same accessibility rules as other static members. If it is declared private, it is accessible only within the enclosing class, and so forth.
The Operation class should be a public static member class of the Calculator class. Clients of the Calculator class could then refer to operations using names like Calculator.Operation.PLUS and Calculator.Operation.MINUS.
One common use of an anonymous class is to create a function object, such as a Comparator
Each instance of a nonstatic member class is implicitly associated with an enclosing instance of its containing class.
// Typical use of an anonymous class
Arrays.sort(args, new Comparator() {
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
----------------Methods---------------
-------------------------------------------------------
Item 23: Check parameters for validity
Most methods and constructors have some restrictions on what values may be passed into their parameters.
Typically the exception will be IllegalArgumentException, IndexOutOfBoundsException, or NullPointerException
Nonpublic methods should generally check their parameters using assertions rather than normal checks. If you are using a release of the platform that supports assertions (1.4 or later), you should use the assert construct; otherwise you should use a makeshift assertion mechanism.
Item 24: Make defensive copies when needed
public final class Period {
private final Date start; private final Date end; public
Period(Date start, Date end) { //Constructor
if (start.compareTo(end) > 0) throw new IllegalArgumentException(start + " after "+ end); this.start = start; this.end = end; }
public Date start() {return start;}
public Date end() {return end;}
... // Remainder omitted
}
// Attack the internals of a Period instance from client program
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
end.setYear(78); // Modifies internals of p!
To protect the internals of a Period instance from this sort of attack, it is essential to make a defensive copy of each mutable parameter to the constructor and to use the copies as components of the Period instance in place of the originals:
// Repaired constructor - makes defensive copies of parameters
public Period(Date start, Date end) {
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0) throw new IllegalArgumentException(start +" after "+ end); }
defensive copies are made before checking the validity of the parameters, and the validity check is performed on the copies rather than on the originals.
do not use the clone method to make a defensive copy of a parameter whose type is subclassable by untrusted parties.
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.end().setYear(78); // Modifies internals of p!
To defend against the second attack, merely modify the accessors to return defensive copies of mutable internal fields:
// Repaired accessors - make defensive copies of internal fields
public Date start() {
return new Date(start.getTime());
}
public Date end() {
return new Date(end.getTime());
}
Item 26: Use overloading judiciously
The choice of which overloading to invoke is made at compile time.
Selection among overloaded methods is static, while selection among overridden methods is dynamic.
Item 27: Return zero-length arrays, not nulls
There is no reason ever to return null from an array-valued method instead of returning a zero-length array.
Item 28: Write doc comments for all exposed API elements
Notice the use of HTML metacharacters and tags in this doc comment. The Javadoc utility translates doc comments into HTML
------------------General Programming-------------
-------------------------------------------------------------------------------
Item 29: Minimize the scope of local variables
Prefer for loops to while loops, assuming the contents of the loop variable(s) aren't needed after the loop terminates.
Item 30: Know and use the libraries
The Collections Framework substantially reduces the amount of code necessary to do many mundane tasks. For example, suppose you have a vector of strings, and you want to sort it alphabetically. This one-liner does the job:
Collections.sort(v);
If you want to do the same thing ignoring case distinctions, use the following:
Collections.sort(v, String.CASE_INSENSITIVE_ORDER);
Item 31: Avoid float and double if exact answers are required
The float and double types are particularly ill-suited for monetary calculations because it is impossible to represent 0.1 (or any other negative power of ten) as a float or double exactly.
Item 32: Avoid strings where other types are more appropriate
Avoid the natural tendency to represent objects as strings when better data types exist or can be written.
Item 33: Beware the performance of string concatenation
Using the string concatenation operator repeatedly to concatenate n strings requires time quadratic in n. It is an unfortunate consequence of the fact that strings are immutable .When two strings are concatenated, the contents of both are copied.
use a StringBuffer in place of a String
Item 34: Refer to objects by their interfaces
If appropriate interface types exist, parameters, return values, variables, and fields should all be declared using interface types.
If you decide that you want to switch implementations, all you have to do is change the class name in the constructor (or use a different static factory)
// Good - uses interface as type
List subscribers = new Vector();
rather than this:
// Bad - uses class as type!
Vector subscribers = new Vector();
For example, the first declaration could be changed to read
List subscribers = new ArrayList();
and all of the surrounding code would continue to work.
The code surrounding the first declaration depended on the fact that Vector is synchronized, then it would be incorrect to substitute ArrayList for Vector in the declaration.
If an object belongs to such a class-based framework, it is preferable to refer to it by the relevant base class, which is typically abstract, rather than by its implementation class.
Item 35: Prefer interfaces to reflection
The reflection facility, java.lang.reflect, offers programmatic access to information about loaded classes. Given a Class instance, you can obtain Constructor, Method, and Field instances representing the constructors, methods, and fields of the class represented by the Class instance. These objects provide programmatic access to the class's member names, field types, method signatures, and so on.
Reflection allows one class to use another, even if the latter class did not exist when the former was compiled. This power, however, comes at a price:
You lose all the benefits of compile-time type checking, including exception checking.
The code required to perform reflective access is clumsy and verbose. It is tedious to write and difficult to read.
Performance suffers.
load classes on demand and use reflection to find out what methods and constructors they support.
Reflection is also appropriate for use in RPC systems to eliminate the need for stub compilers.
For many programs that must use a class unavailable at compile time, there exists at compile time an appropriate interface or superclass by which to refer to the class. If this is the case, you can create instances reflectively and access them normally via their interface or superclass.
The order in which these arguments are printed depends on the class specified in the first argument. If you specify “java.util.HashSet,” they're printed in apparently random order; if you specify “java.util.TreeSet,” they're printed in alphabetical order, as the elements in a TreeSet are sorted:
Class cl = Class.forName(args[0]);
Set s = (Set) cl.newInstance();
Disadvantages of reflection
Generates run-time errors, all of which would have been compile-time errors
It takes twenty lines of tedious code to generate an instance of the class from its name, whereas a constructor invocation would fit neatly on a single line.
Item 36: Use native methods judiciously
The Java Native Interface (JNI) allows Java applications to call native methods, which are special methods written in native programming languages such as C or C++.
class HelloWorld {
static {
System.loadLibrary("HelloWorld");
}
private native void print();
public static void main(String[] args) {
new HelloWorld().print();
}
}
javac HelloWorld.java
This command will generate a HelloWorld.class file in the current directory
javah -jni HelloWorld
The command shown above generates a file named HelloWorld.h.
Writing the C implementation (HelloWorld.c) of the native method
The JNI-style header file generated by javah helps you to write C or C++ implementations for the native method. The function that you write must follow the -prototype specified in the generated header file. You can implement the Hello-World.print method in a C file HelloWorld.c as follows:
#include
#include
#include
"HelloWorld.h" JNIEXPORT
void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) {
printf("Hello World!\n");
return;
}
Compiling the C implementation into a native library, creating Hello-World.dll or libHello-World.so
Now that all the necessary C code is written, you need to compile Hello-World.c and build this native library.
Item 37: Optimize judiciously
Item 38: Adhere to generally accepted naming conventions

---------------Exceptions----------------
------------------------------------------------------------
Item 39:Use exceptions only for exceptional conditions
// Horrible abuse of exceptions. Don't ever do this!
try {
int i = 0;
while(true)
a[i++].f();
} catch(ArrayIndexOutOfBoundsException e) {}
The infinite loop terminates by throwing, catching, and ignoring an ArrayIndexOutOfBoundsException when it attempts to access the first array element outside the bounds of the array.
Item 40:Use checked exceptions for recoverable conditions and run-time exceptions for programming errors
three kinds of throwables: checked exceptions, runtime exceptions, and errors.
Use checked exceptions for conditions from which the caller can reasonably be expected to recover. By throwing a checked exception, you force the caller to handle the exception in a catch clause or to propagate it outward
There are two kinds of unchecked throwables: run-time exceptions and errors.
They are identical in their behavior: Both are throwables that needn't, and generally shouldn't, be caught. If a program throws an unchecked exception or an error, it is generally the case that recovery is impossible and continued execution would do more harm than good. If a program does not catch such a throwable, it will cause the current thread to halt with an appropriate error message.
All of the unchecked throwables you implement should subclass RuntimeException.
Checked Exception: NamingException, FileNotFoundException
Uncheked Exceptions: NullPointerException, ArrayOutOfBoundException
Errors: OutofMemoryException, StackOverflowException, IOError
Item 41:Avoid unnecessary use of checked exceptions
the catch block almost always has the character of an assertion failure. The checked nature of the exception provides no benefit to the programmer, but it requires effort and complicates programs.
} catch(TheCheckedException e) { throw new Error("Assertion error"); // Should never happen!
}
How about this?
} catch(TheCheckedException e) { e.printStackTrace(); // Oh well, we lose.
System.exit(1); }
Item 42:Favor the use of standard exceptions

Item 43: Throw exceptions appropriate to the abstraction
higher layers should catch lower-level exceptions and, in their place, throw exceptions that are explainable in terms of the higher-level abstraction.
// Exception Translation or Exception Chaining
try {
// Use lower-level abstraction to do our bidding
...
} catch(LowerLevelException e) {
throw new HigherLevelException(...);
}
it may be appropriate to log the exception using some appropriate logging facility such as java.util.logging, which was introduced in release 1.4.
Item 44:Document all exceptions thrown by each method
Always declare checked exceptions individually, and document precisely the conditions under which each one is thrown using the Javadoc @throws tag.
Item 46:Strive for vetbfailure atomicity
After an object throws an exception, it is generally desirable that the object still be in a well-defined, usable state, even if the failure occurred in the midst of performing
an operation. This is especially true for checked exceptions, from which the caller is expected to recover. Generally speaking, a failed method invocation should leave the object in the state that it was in prior to the invocation. A method with this property is said to be failure atomic.
If an object is immutable, failure atomicity is free. If an operation fails, it may prevent a new object from getting created, but it will never leave an existing object in an inconsistent state because the state of each object is consistent when it is created and can't be modified thereafter.
For methods that operate on mutable objects, the most common way to achieve failure atomicity is to check parameters for validity before performing the operation
Item 47:Don't ignore exceptions
An empty catch block defeats the purpose of exceptions
-------------------Threads----------------
------------------------------------------------------------
Item 48: Synchronize access to shared mutable data
The synchronized keyword ensures that only a single thread will execute a statement or block at a time.
Not only does synchronization prevent a thread from observing an object in an inconsistent state, but it also ensures that objects progress from consistent state to consistent state by an orderly sequence of state transitions that appear to execute sequentially.
The language guarantees that reading or writing a single variable is atomic unless the variable is of type long or double. In other words, reading a variable other than a long or double is guaranteed to return a value that was stored into that variable by some thread, even if multiple threads modify the variable concurrently without synchronization.
While the atomicity guarantee ensures that a thread will not see a random value when reading atomic data, it does not guarantee that a value written by one thread will be visible to another: Synchronization is required for reliable communication between threads as well as for mutual exclusion.
Next, consider the process of stopping a thread. While the platform provides methods for involuntarily stopping a thread, these methods are deprecated because they are inherently unsafe—their use can result in object corruption. The recommended method of stopping a thread is simply to have the thread poll some field whose value can be changed to indicate that the thread is to stop itself. The field is typically a boolean or an object reference.
public void run() { //in run method
boolean done = false;
while (!stopRequested && !done) {
... // do what needs to be done.
}
}
The volatile modifier guarantees that any thread that reads a field will see the most recently written value.
whenever multiple threads share mutable data, each thread that reads or writes the data must obtain a lock.
Item 49: Avoid excessive synchronization
To avoid the risk of deadlock, never cede control to the client within a synchronized method or block. In other words, inside a synchronized region, do not invoke a public or protected method that is designed to be overridden. (Such methods are typically abstract, but occasionally they have a concrete default implementation.) From the perspective of the class containing the synchronized region, such a method is alien. The class has no knowledge of what the method does and no control over it. A client could provide an implementation of an alien method that creates another thread that calls back into the class.
do as little work as possible inside synchronized regions. Obtain the lock, examine the shared data, transform the data as necessary, and drop the lock.
When you are designing a mutable class, think about whether it should do its own synchronization.
classes StringBuffer and BufferedInputStream are thread-safe. Are almost always used by a single thread, so the locking they do is usually unnecessary.
Item 50: Never invoke wait outside a loop
The Object.wait method is used to make a thread wait for some condition. It must be invoked inside a synchronized region that locks the object on which it is invoked. This is the standard idiom for using the wait method:
synchronized (obj) {
while (
obj.wait();
... // Perform action appropriate to condition
}
Always use the wait loop idiom to invoke the wait method. Never invoke it outside of a loop. The loop serves to test the condition before and after waiting.
It is often said that you should always use notifyAll. This is reasonable, conservative advice, assuming that all wait invocations are inside while loops. It will always yield correct results because it guarantees that you'll wake the threads that need to be awakened. You may wake some other threads too, but this won't affect the correctness of your program. These threads will check the condition for which they're waiting and, finding it false, will continue waiting.
Item 51: Don't depend on the thread scheduler
Any program that relies on the thread scheduler for its correctness or performance is likely to be nonportable.
There should be few runnable threads at any given time. This leaves the thread scheduler with very little choice: It simply runs the runnable threads till they're no longer runnable. As a consequence, the program's behavior doesn't vary much even under radically different thread scheduling algorithms.
Threads should not busy-wait, repeatedly checking a data structure waiting for something to happen. Besides making the program vulnerable to the vagaries of the scheduler, busy-waiting can greatly increase the load on the processor, reducing the amount of useful work that other processes can accomplish on the same machine.
A related technique, to which similar caveats apply, is adjusting thread priorities. Thread priorities are among the least portable features of the Java platform.
Thread.yield Causes the currently executing thread object to temporarily pause and allow other threads to execute.
Have Thread.yield is to artificially increase the concurrency of a program during testing.
Item 52: Document thread safety
The following list summarizes the levels of thread safety that a class can support.
- immutable— Instances of this class appear constant to their clients. No external synchronization is necessary. Examples include String, Integer, and BigInteger
- thread-safe— Instances of this class are mutable, but all methods contain sufficient internal synchronization that instances may be used concurrently without the need for external synchronization. Concurrent invocations will appear to execute serially in some globally consistent order. Examples include Random and java.util.Timer.
- conditionally thread-safe— Like thread-safe, except that the class (or an associated class) contains methods that must be invoked in sequence without interference from other threads. To eliminate the possibility of interference, the client must obtain an appropriate lock for the duration of the sequence. Examples include Hashtable and Vector, whose iterators require external synchronization.
- thread-compatible— Instances of this class can safely be used concurrently by surrounding each method invocation (and in some cases, each sequence of method invocations) by external synchronization. Examples include the general purpose collection implementations, such as ArrayList and HashMap.
- thread-hostile— This class is not safe for concurrent use by multiple threads, even if all method invocations are surrounded by external synchronization. The System.runFinalizersOnExit method is thread-hostile, and has been deprecated.
Item 53: Avoid thread groups
Thread groups are largely obsolete.
---------------Serialization----------------
--------------------------------------------------------------
Serialization provides the standard wire-level object representation for remote communication, and the standard persistent data format for the JavaBeans™ component
architecture.
Item 54: Implement Serializable judiciously
When a class implements Serializable, its byte-stream encoding (or serialized form) becomes part of its exported API. Once you distribute a class widely, you are generally required to support the serialized form forever, just as you are required to support all other parts of the exported API.
A simple example of the constraints on evolution that accompany serializability concerns stream unique identifiers, more commonly known as serial version UIDs. Every serializable class has a unique identification number associated with it. If you do not specify the identification number explicitly by declaring a private static final long field named serialVersionUID, the system automatically generates it by applying a complex deterministic procedure to the class. The automatically generated value is affected by the class's name, the names of the interfaces it implements, and all of its public and protected members.
Normally, objects are created using constructors; serialization is an extralinguistic mechanism for creating objects. Whether you accept the default behavior or override it, deserialization is a “hidden constructor” with all of the same issues as other constructors.
A third cost of implementing Serializable is that it increases the testing burden associated with releasing a new version of a class.
In addition to binary compatibility, you must test for semantic compatibility. In other words, you must ensure both that the serialization-deserialization process succeeds and that it results in a faithful replica of the original object.
Classes designed for inheritance should rarely implement Serializable, and interfaces should rarely extend it.
There is one caveat regarding the decision not to implement Serializable. If a class that is designed for inheritance is not serializable, it may be impossible to write a serializable subclass. Specifically, it will be impossible if the superclass does not provide an accessible parameterless constructor. Therefore you should consider providing a parameterless constructor on nonserializable classes designed for inheritance.
Inner classes should rarely, if ever, implement Serializable. They use compiler-generated synthetic fields to store references to enclosing instances and to store values of local variables from enclosing scopes. How these fields correspond to the class definition is unspecified, as are the names of anonymous and local classes. Therefore, the default serialized form of an inner class is ill-defined. A static member class can, however, implement Serializable.
Item 55: Consider using a custom serialized form
The ideal serialized form of an object contains only the logical data represented by the object. It is independent of the physical representation.
The default serialized form is likely to be appropriate if an object's physical representation is identical to its logical content.
Item 56: Write readObject methods defensively
When an object is deserialized, it is critical to defensively copy any field containing an object reference that a client must not possess.
Any time you write a readObject method, adopt the mind-set that you are writing a public constructor that must produce a valid instance regardless of what byte stream it is given. Do not assume that the byte stream represents an actual serialized instance.
Item 57: Provide a readResolve method when necessary
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.
If the Elvis class is made to implement Serializable, the following readResolve method suffices to guarantee the singleton property:
private Object readResolve() throws ObjectStreamException {
// Return the one true Elvis and let the garbage collector
// take care of the Elvis impersonator.
return INSTANCE;
}
This method ignores the deserialized object, simply returning the distinguished Elvis instance created when the class was initialized.
A readResolve method is necessary not only for singletons, but for all other instancecontrolled classes
The accessibility of the readResolve method is significant. If you place a readResolve method on a final class, such as a singleton, it should be private.
No comments:
Post a Comment