Item 37: Use marker interfaces to define types
Marker interface contains no method declarations, which indicates some property or features. The typical marker interface is Serialize interface.
Item 38: Check parameters for validity
Check and restrict the parameters of functions.
In general, if a class has mutable components that it gets from or returns to its clients, the class must defensively copy these components.
Defensive copy usually implemented by:
Item 40: Design method signatures carefully
Avoid long parameter lists. Divide them to several methods or use helper method and helper class.
Favor interfaces over classes.
Prefer two-element enum types to boolean parameters for clearness and extendability.
Item 41: Use overloading judiciously
Selection among overloaded methods is static (at the compile time), while selection among overridden methods is dynamic.
Refrain using of overloading methods with same number of parameters.
If you can not avoid that, try avoiding parameters that can be passed to different overloadings by casts.
Item 42: Use varargs judiciously
Do not use varargs unless you really need it and benefit from it.
Varargs is expensive in resources.
Arrays.asList() is tricky. It returns List<Integer> when the argument is Integer[] and returns List<int[]> when the argument is int[].
Item 43: Return empty arrays or collections, not nulls
Returning null requires extra judgement in the client side.
Use new Object1[0] for arrays and emptyList(), emptySet() and emptyMap() for containers.
Item 44: Write doc comments for all exposed API elements
@param tag for the parameters. @return for return values. @throws for exception may throw.
Care the HTML metacharacters in doc comments.
Write succinct and nice comment as the summary description in the beginning.
For methods and constructors: verb phrase .
Item 45: Minimize the scope of local variables
Minimize the scope of a local variable by declaring it where it is first used.
Prefer for loops to while loops.
Item 46: Prefer for-each loops to traditional for loops
Use the for each loops to iterate the arrays.
Exception:
Be familiar with the contents of java.lang, java.util, and, to a lesser extent, java.io.
Item 48: Avoid float and double if exact answers are required
Use the BigDecimal or int or long instead.
int for number with less than 9 digits and long for 19 digits.
Item 49: Prefer primitive types to boxed primitives
“==” operation to mixture of primitive and boxed primitive compares the reference identity but not value.
Use autoboxing carefully.
Item 50: Avoid strings where other types are more appropriate
Do not use string type in everywhere.
Item 51: Beware the performance of string concatenation
Use append() of StringBuilder instead.
Item 52: Refer to objects by their interfaces
Using interface as parameter type make the program more flexible.
List<Subscriber> subscribers = new Vector<Subscriber>();
List<Subscriber> subscribers = new ArrayList<Subscriber>();
Item 53: Prefer interfaces to reflection
Reflection loses all information of complile-time check.
Reflection is only used at design time.
When using the class unknown at compile time, try to only instantiate them by reflection. Access fields and call methods using interfaces or superclasses.
Item 54: Use native methods judiciously
Avoid using native code unless you really need it.
Item 55: Optimize judiciously
Weshould forget about small efficiencies, say about 97% of the time: prema-ture optimization is the root of all evil. –Donald E. Knuth.
Write good programs but not fast programs.
Item 56: Adhere to generally accepted naming conventions
Generally, follow The Java Language Specification as conventions.
Package com.google.inject, org.joda.time.format
Class or Interface Timer, FutureTask, LinkedHashMap, HttpServlet
Method or Field remove, ensureCapacity, getCrc
Constant Field MIN_VALUE, NEGATIVE_INFINITY
Local Variable i, xref, houseNumber
Type Parameter T, E, K, V, X, T1, T2
Item 57: Use exceptions only for exceptional conditions
Do not use the exception for control flow, exception is designed for exceptional condition.
Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors
Checked exception is used in recoverable case. For that, it need to provide information or methods to help the caller to recover.
Item 59: Avoid unnecessary use of checked exceptions
Avoid using the checked exception unless:
Some commonly used exceptions:
IllegalArgumentException: Non-null parameter value is inappropriate
IllegalStateException: Object state is inappropriate for method invocation
NullPointerException: Parameter value is null where prohibited
IndexOutOfBoundsException: Index parameter value is out of range
ConcurrentModificationException: Concurrent modification of an object has been detected where it is prohibited
UnsupportedOperationException: Object does not support method
Item 61: Throw exceptions appropriate to the abstraction
If it is impossible to prevent the occurring of exception in lower level, propagate it to higher level by catching and rethrowing.
Try to log the exception information if detailed information is needed.
Item 62: Document all exceptions thrown by each method
Document the exceptions by Javadoc @throws tag. Do not “throws” unchecked exceptions.
Item 63: Include failure-capture information in detail messages
Include failure-capture information in checked exceptions. Those information is useful in recovering from failure.
Item 64: Strive for failure atomicity
Any generated exception should leave the object in the same state it was in prior to the method invocation.
Example:
Do not try to maintain the failure atomicity when throwing errors.
Item 65: Don’t ignore exceptions
Do not use empty catch block to ignore the exception. Throw it outward at least if you do not know how to handle it.
Item 66: Synchronize access to shared mutable data
Synchronization includes two parts: mutual exclusion and visibility. Without synchronization, one thread’s changes might not be visible to other threads.
Do not use Thread.stop as it is depreciated.
Synchronization has no effect unless both read and write operations are synchronized.
Volatile and Atomic types should be carefully used.
Item 67: Avoid excessive synchronization
Do not call alien methods in synchronized block. Doing this is uncontrollable and may cause exceptions and deadlock.
Use concurrent containers like CopyOnWriteArrayList to separate the data writing and reading. This is particularly useful to the situation in which writing data is happened occasionally.
In a multicore world, the real cost of excessive synchronization is not the CPU time spent obtaining locks; it is the lost opportunities for parallelism and the delays imposed by the need to ensure that every core has a consistent view of memory.
Do not synchronize the class internally unless you have good reason.
Item 68: Prefer executors and tasks to threads
Executor framework separate the task and mechanism of executing. So use executors prior to Thread.
Using Executors.newFixedThreadPool under heavy loading situations.
Using ScheduledThreadPoolExecutor prior to Timer when multiple timing tasked are required.
Item 68: Prefer executors and tasks to threads
The higher-level utilities in java.util.concurrent fall into three categories:the Executor Framework, concurrent collections; and synchronizers.
Utilities in the concurrent library should be considered first before wait() and notify().
Use ConcurrentHashMap in preference to Collections.synchronizedMap or Hashtable.
Common synchronizers include CyclicBarrier, CountdownLatch and Semaphore.
Item 70: Document thread safety
The presence of the synchronized modifierin a method declaration is an implementation detail, not a part of its exported API.
To enable safe concurrent use, a class must clearly document what level of thread safety it supports.
levels of thread safety:
Lazy initialization decreases the cost of initializing a class or creating an instance, at the expense of increasing the cost of accessing the lazily initialized field. It may be worthwhile when only part of instances will be initialized in practice.
Use a synchronized accessor to the getfield method to ensure the concurrency.
Use the lazy initialization holder class idiom for static field.
Use the double-check idiom for instance field.
Item 72: Don’t depend on the thread scheduler
Do not rely on scheduler for correctness of program.
Do not let the thread busy-wait.
Use Thread.sleep(1) instead of Thread.yield() for increasing concurrency.
Item 73: Avoid thread groups
Thread groups are obsolete.
Item 74: Implement Serializable judiciously
Long term cost of implementing Serializable include:
Decreases the flexi-bility to change a class’s implementation once it has been released.
Increase the likelihood of bug and security holes.
Increase the burden of testing.
Classes designed for inheritance should rarely implement Serializable, and interfaces should rarely extend it.
Exceptions: Throwable, Component, and HttpServlet, etc.
Item 75: Consider using a custom serialized form
Use the default serialized form only when an object’s phys-ical representation is identical to its logical content.
Disadvantages of inappropriate default serialized form:
Before deciding to make a field nontransient, convince yourself that its value is part of the logical state of the object.
Declare an explicit serial version UID in every serializable class you write, to tackle the version problem.
Item 76: Write readObject methods defensively
Make defensive copy of fields in readObject() method is necessary like in the constructor.
For classes with object reference fields that must remain private, defensively copy each object in such a field.
Check any invariants and throw an InvalidObjectException if a check fails.
Do not invoke any overridable methods in the constructor or readObject() method.
Item 77: For instance control, prefer enum types to readResolve
The instance control (e.g, Singleton) is violated without readResolve() method after serialization.
All instance fields with object reference types must be declared transient if using the readResolve() to do the instance control.
Instance control through Enum is preferred to the readResolve().
Item 78: Consider serialization proxies instead of serialized instances
Serialization proxy pattern is implemented based on an inner static class with a single constructor.
Use writeReplace() of enclosing class to write a proxy instance instead of the instance of enclosing class.
Use readResolve() method to return a instance of enclosing class at the time of deserialization, since the method in the inner class is able to call the constructor of enclosing class.
Two limitations of the serialization proxy pattern:
It is not compatible with classes that are extendable by their clients (in that time, the enclosing class has not been initialized).
It is not compatible with some classes whose object graphs contain circularities.
Serialization proxy pattern is more secure, but with higher expense.
Source
Marker interface contains no method declarations, which indicates some property or features. The typical marker interface is Serialize interface.
Item 38: Check parameters for validity
Check and restrict the parameters of functions.
- Throw Exception
- Assert
In general, if a class has mutable components that it gets from or returns to its clients, the class must defensively copy these components.
Defensive copy usually implemented by:
- clone() method
- copy constructor
- static factory
Item 40: Design method signatures carefully
Avoid long parameter lists. Divide them to several methods or use helper method and helper class.
Favor interfaces over classes.
Prefer two-element enum types to boolean parameters for clearness and extendability.
Item 41: Use overloading judiciously
Selection among overloaded methods is static (at the compile time), while selection among overridden methods is dynamic.
Refrain using of overloading methods with same number of parameters.
If you can not avoid that, try avoiding parameters that can be passed to different overloadings by casts.
Item 42: Use varargs judiciously
Do not use varargs unless you really need it and benefit from it.
Varargs is expensive in resources.
Arrays.asList() is tricky. It returns List<Integer> when the argument is Integer[] and returns List<int[]> when the argument is int[].
Item 43: Return empty arrays or collections, not nulls
Returning null requires extra judgement in the client side.
Use new Object1[0] for arrays and emptyList(), emptySet() and emptyMap() for containers.
Item 44: Write doc comments for all exposed API elements
@param tag for the parameters. @return for return values. @throws for exception may throw.
Care the HTML metacharacters in doc comments.
Write succinct and nice comment as the summary description in the beginning.
For methods and constructors: verb phrase .
- Returns the number of elements in this collection.
- A task that can be scheduled for one-time or repeated execution by a Timer.
Item 45: Minimize the scope of local variables
Minimize the scope of a local variable by declaring it where it is first used.
Prefer for loops to while loops.
Item 46: Prefer for-each loops to traditional for loops
Use the for each loops to iterate the arrays.
Exception:
- you need to remove the elements.
- you need to change the value of elements.
- special control for the pace of iteration.
Be familiar with the contents of java.lang, java.util, and, to a lesser extent, java.io.
Item 48: Avoid float and double if exact answers are required
Use the BigDecimal or int or long instead.
int for number with less than 9 digits and long for 19 digits.
Item 49: Prefer primitive types to boxed primitives
“==” operation to mixture of primitive and boxed primitive compares the reference identity but not value.
Use autoboxing carefully.
Item 50: Avoid strings where other types are more appropriate
Do not use string type in everywhere.
Item 51: Beware the performance of string concatenation
Use append() of StringBuilder instead.
Item 52: Refer to objects by their interfaces
Using interface as parameter type make the program more flexible.
List<Subscriber> subscribers = new Vector<Subscriber>();
List<Subscriber> subscribers = new ArrayList<Subscriber>();
Item 53: Prefer interfaces to reflection
Reflection loses all information of complile-time check.
Reflection is only used at design time.
When using the class unknown at compile time, try to only instantiate them by reflection. Access fields and call methods using interfaces or superclasses.
Item 54: Use native methods judiciously
Avoid using native code unless you really need it.
Item 55: Optimize judiciously
Weshould forget about small efficiencies, say about 97% of the time: prema-ture optimization is the root of all evil. –Donald E. Knuth.
Write good programs but not fast programs.
Item 56: Adhere to generally accepted naming conventions
Generally, follow The Java Language Specification as conventions.
Package com.google.inject, org.joda.time.format
Class or Interface Timer, FutureTask, LinkedHashMap, HttpServlet
Method or Field remove, ensureCapacity, getCrc
Constant Field MIN_VALUE, NEGATIVE_INFINITY
Local Variable i, xref, houseNumber
Type Parameter T, E, K, V, X, T1, T2
Item 57: Use exceptions only for exceptional conditions
Do not use the exception for control flow, exception is designed for exceptional condition.
Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors
Checked exception is used in recoverable case. For that, it need to provide information or methods to help the caller to recover.
Item 59: Avoid unnecessary use of checked exceptions
Avoid using the checked exception unless:
- the exception can not avoided by proper use of API.
- Handling exception brings benefits.
Some commonly used exceptions:
IllegalArgumentException: Non-null parameter value is inappropriate
IllegalStateException: Object state is inappropriate for method invocation
NullPointerException: Parameter value is null where prohibited
IndexOutOfBoundsException: Index parameter value is out of range
ConcurrentModificationException: Concurrent modification of an object has been detected where it is prohibited
UnsupportedOperationException: Object does not support method
Item 61: Throw exceptions appropriate to the abstraction
If it is impossible to prevent the occurring of exception in lower level, propagate it to higher level by catching and rethrowing.
Try to log the exception information if detailed information is needed.
Item 62: Document all exceptions thrown by each method
Document the exceptions by Javadoc @throws tag. Do not “throws” unchecked exceptions.
Item 63: Include failure-capture information in detail messages
Include failure-capture information in checked exceptions. Those information is useful in recovering from failure.
Item 64: Strive for failure atomicity
Any generated exception should leave the object in the same state it was in prior to the method invocation.
Example:
1
2
3
4
5
6
7
| public Object pop() { if (size == 0 ) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null ; // Eliminate obsolete reference return result; } |
Item 65: Don’t ignore exceptions
Do not use empty catch block to ignore the exception. Throw it outward at least if you do not know how to handle it.
Item 66: Synchronize access to shared mutable data
Synchronization includes two parts: mutual exclusion and visibility. Without synchronization, one thread’s changes might not be visible to other threads.
Do not use Thread.stop as it is depreciated.
Synchronization has no effect unless both read and write operations are synchronized.
Volatile and Atomic types should be carefully used.
Item 67: Avoid excessive synchronization
Do not call alien methods in synchronized block. Doing this is uncontrollable and may cause exceptions and deadlock.
Use concurrent containers like CopyOnWriteArrayList to separate the data writing and reading. This is particularly useful to the situation in which writing data is happened occasionally.
In a multicore world, the real cost of excessive synchronization is not the CPU time spent obtaining locks; it is the lost opportunities for parallelism and the delays imposed by the need to ensure that every core has a consistent view of memory.
Do not synchronize the class internally unless you have good reason.
Item 68: Prefer executors and tasks to threads
Executor framework separate the task and mechanism of executing. So use executors prior to Thread.
Using Executors.newFixedThreadPool under heavy loading situations.
Using ScheduledThreadPoolExecutor prior to Timer when multiple timing tasked are required.
Item 68: Prefer executors and tasks to threads
The higher-level utilities in java.util.concurrent fall into three categories:the Executor Framework, concurrent collections; and synchronizers.
Utilities in the concurrent library should be considered first before wait() and notify().
Use ConcurrentHashMap in preference to Collections.synchronizedMap or Hashtable.
Common synchronizers include CyclicBarrier, CountdownLatch and Semaphore.
Item 70: Document thread safety
The presence of the synchronized modifierin a method declaration is an implementation detail, not a part of its exported API.
To enable safe concurrent use, a class must clearly document what level of thread safety it supports.
levels of thread safety:
- immutable
- unconditionally thread-safe
- conditionally thread-safe
- not thread-safe
Lazy initialization decreases the cost of initializing a class or creating an instance, at the expense of increasing the cost of accessing the lazily initialized field. It may be worthwhile when only part of instances will be initialized in practice.
Use a synchronized accessor to the getfield method to ensure the concurrency.
Use the lazy initialization holder class idiom for static field.
1
2
3
4
5
| // Lazy initialization holder class idiom for static fields private static class FieldHolder { static final FieldType field = computeFieldValue(); } static FieldType getField() { return FieldHolder.field; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
| // Double-check idiom for lazy initialization of instance fields private volatile FieldType field; FieldType getField() { FieldType result = field; if (result == null ) { // First check (no locking) synchronized ( this ) { result = field; if (result == null ) // Second check (with locking) field = result = computeFieldValue(); } } return result; } |
Do not rely on scheduler for correctness of program.
Do not let the thread busy-wait.
Use Thread.sleep(1) instead of Thread.yield() for increasing concurrency.
Item 73: Avoid thread groups
Thread groups are obsolete.
Item 74: Implement Serializable judiciously
Long term cost of implementing Serializable include:
Decreases the flexi-bility to change a class’s implementation once it has been released.
Increase the likelihood of bug and security holes.
Increase the burden of testing.
Classes designed for inheritance should rarely implement Serializable, and interfaces should rarely extend it.
Exceptions: Throwable, Component, and HttpServlet, etc.
Item 75: Consider using a custom serialized form
Use the default serialized form only when an object’s phys-ical representation is identical to its logical content.
Disadvantages of inappropriate default serialized form:
- permanently ties the exported API to the current internal representation.
- consume excessive space.
- consume excessive time (graph traversal).
- stack overflow.
Before deciding to make a field nontransient, convince yourself that its value is part of the logical state of the object.
Declare an explicit serial version UID in every serializable class you write, to tackle the version problem.
Item 76: Write readObject methods defensively
Make defensive copy of fields in readObject() method is necessary like in the constructor.
For classes with object reference fields that must remain private, defensively copy each object in such a field.
Check any invariants and throw an InvalidObjectException if a check fails.
Do not invoke any overridable methods in the constructor or readObject() method.
Item 77: For instance control, prefer enum types to readResolve
The instance control (e.g, Singleton) is violated without readResolve() method after serialization.
All instance fields with object reference types must be declared transient if using the readResolve() to do the instance control.
Instance control through Enum is preferred to the readResolve().
Item 78: Consider serialization proxies instead of serialized instances
Serialization proxy pattern is implemented based on an inner static class with a single constructor.
Use writeReplace() of enclosing class to write a proxy instance instead of the instance of enclosing class.
Use readResolve() method to return a instance of enclosing class at the time of deserialization, since the method in the inner class is able to call the constructor of enclosing class.
Two limitations of the serialization proxy pattern:
It is not compatible with classes that are extendable by their clients (in that time, the enclosing class has not been initialized).
It is not compatible with some classes whose object graphs contain circularities.
Serialization proxy pattern is more secure, but with higher expense.
Source