Josh Bloch says
1. Consider static factory methods instead of constructors- have names (unlike constructors)
- are not required to create a new object each time they're invoked (unlike constructors)
- can return an object of any subtype of their return type (unlike constructors)
- reduce the verbosity of creating parameterized type instances
- disadvantage of providing only static factory methods is that classes without public or protected constructors cannot be subclassed
- are not readily distinguishable from other static methods
2. Consider a builder when faced with many constructor parameters- the telescoping constructor pattern works, but it is hard to write and read client code when there are many parameters
- a JavaBean can not be immutable and may be in an inconsistent state partway through its construction
- Builder pattern simulates named optional parameters
- Class.newInstance breaks compile-time exception checking
- Builder pattern is a good choice when designing classes whose constructor or static factories would have more than a handful of parameters
3. Enforce the singleton property with a private constructor or an enum type- singletons can make it difficult to test a singleton's clients
- a single-element enum type is the best way to implement a singleton
4. Enforce noninstantiability with a private constructor- attempting to enforce noninstantiability by making a class abstract does not work
5. Avoid creating unnecessary objects- prefer primitives to boxed primitives and watch out for unintentional autoboxing
6. Eliminate obsolete object references- nulling-out object references should be the exception rather than the norm
- be alert for memory leaks whenever a class manages its own memory
- common source of memory leaks: caches, listeners and other callbacks
7. Avoid finalizers- are unpredictable, often dangerous, and generally unnecessary
- never do anything time-critical in a finalizer
- never depend on a finalizer to update critical persistent state
- severe performance penalty for using finalizers
- provide explicit termination method to be used with try-finally to ensure termination
- finalizer should log a warning if it finds that the resource has not been terminated
8. Obey the general contract when overriding equals - do not override equals if
-- each instance is inherently unique
-- there is no need for a logical equality test
-- superclass equals is appropriate
-- class is private or package-private and you know that equals will never be invoked
- if equals contract is violated you don't know how other objects will behave when confronted with your object
- there is no way to extend an instantiable class and add a value component while preserving the equals contract
- in your equals don't depend on unreliable resources
9. Always override hashCode when you override equals- equal objects must have equal hash codes
- don't exclude significant parts of an object from the hash code computation to improve performance
10. Always override toString- makes class more pleasant to use
- should return all interesting information contained in the object
- clearly document your intentions in specifying or not specifying the toString format
- provide programmatic access to all of the information contained in the value returned by toString
11. Override clone judiciously- if you override clone in a non-final class you should return an object obtained by invoking super.clone
- a class that implements Cloneable should provide a properly functioning clone method
- never make the client do anything the library can do for the client
- clone functions as another constructor: do not harm original object and properly establish invariants on the clone
- clone architecture is incompatible with normal use of final fields referring to mutable objects
- you're better off providing an alternative means of object copying (copy constructor or copy factory), or simply not prividing the capability
12. Consider implementing Comparable13. Minimize the accessibility of classes and members- instance fields should never be public
- classes with public mutable fields are not thread-safe
- a class must not have a public static final array field, or a getter that returns such a field
14. In public classes, use accessor methods, not public fields- if a class is private or package-private there is nothing inherently wrong with exposing its data fields
15. Minimize mutability- to make class immutable
-- don't provide methods that modify the object's state
-- ensure that class can't be extended
-- make all fields private and final
-- ensure exclusive access to any mutable components (make defensive copies)
- immutable objects are simple and thread-safe and can be shared freely
- classes should be immutable unless there's a very good reason to make them mutable
- if a class nannot be made immutable, limit its mutability as much as possible
- make every field final unless there is a compelling reason to make it non-final
16. Favor composition over inheritance- inheritance violates encapsulation (unlike method invocation)
17. Design and document for inheritance or else prohibit it - a class must document its self-use of overridable methods
- may have to provide hooks into its internal workings in the form of protected methods
- test your class by writing subclasses
- constructors, clone and readObject must not invoke overridable methods (directly or indirectly)
- prohibit subclassing in classes that are not designed and documented to be safely subclassed
18. Prefer interfaces to abstract classes- existing classes can be easily retrofitted to implement a new interface
- interfaces are ideal for defining mixins
- interfaces allow the construction of non-hierarchical type frameworks
- interfaces enable safe, powerful functionality enhancement via the wrapper class idiom
- provide an abstract skeletal implementation class to go with each non-trivial interface that you export
- it is far easier to evlove an abstract class than an interface: once an interface is released it is almost impossible to change
19. Use interfaces only to define types- the constant interface pattern is a poor use of interfaces
20. Prefer class hierarchies to tagged classes- tagged classes are verbose, error-prone and inefficient
- a tagged class is just a pallid imitation of a class hierarchy
21. Use function objects to represent strategies 22. Favor static member classes over non-static- if you declare a member class that does not require access to an enclosing instance, always put a static modifier in its declaration
23. Don't use raw types in new code - if you use raw types you lose all the safety and expressiveness benefits of generics
- you don't use type safety with a paremeterized type like List<Object>
- you can't put any element other than null into a Collection<?>
- must use raw types in class literals
- after instanceof, cast to wildcard type
24. Eliminate unchecked warnings- only as a last resort, if you can prove type-safety, suppress the warning and document your reasoning
- suppress warnings on the smallest scope possible (local variable declaration or method)
25. Prefer lists to arrays26. Favor generic types27. Favor generic methods28. Use bounded wildcards to increase API flexibility - PECS: producer-extends, consumer-super
- don't use wildcard types as return types
- if the user of a class has to think about wildcard types, there is probably something wrong with the class's API
- always use Comparable<? super T> in preference to Comparable<T>
- always use Comparator<? super T> in preference to Comparator<T>
- if a type appears only once in a method declaration replace it with a wildcard
29. Consider type-safe heterogeneous containers - use Class<T> as type token and Class<T>.cast
30. Use enums instead of int constants- to associate data with enum constants, declare instance fields and write a constructor that takes the data and stores it in the fields
- use constant-specific method implementations
- switches on enums are only good for augmenting external enum types with constant-specific behavior
31. Use instance fields instead of ordinals- never derive a value associated with an enum from its ordinal: store it in an instance field instead
32. Use EnumSet instead of bit fields- just because an enumerated type will be used in sets, there is no reason to represent it with bit fields
33. Use EnumMap instead of ordinal indexing- it is rarely appropriate to use ordinals to index arrays: use EnumMap instead
34. Emulate extensible enums with interfaces- while you cannot write an extensible enum type, you can emulate it by writing an interface to go with a basic enum type that implements that interface
35. Prefer annotations to naming patterns - there is simply no reason to use naming patterns now that we have annotations
- use the predefined annotation types where possible
36. Consistently use the Override annotation- use @Override on every method declaration that you believe to override a superclass declaration
37. Use marker interfaces to define types- marker interfaces define a type that is implemented by instances of the marked class - marker annotations do not
- if you find yourself writing a marker annotation type whose target is ElementType.TYPE, take the time to figure out whether it really should be an annotation type, or whether a marker interface would bemore appropriate
38. Check parameters for validity39. Make defensive copies when needed- you must program defensively, with the assumption that clients of your class will do their best to destroy its invariants
- it is essential to make a defensive copy of each mutable parameter to the constructor
- defensive copies are made before checking the validity of the parameters, and the validity check is performed on the copies rather than the originals
- do not use the clone method to make a defensive copy of a parameter whose type is publicly subclassable
- return defensive copies of mutable internal fields
40. Design method signatures carefully- chose method names carefully
- don't go overboard in providing convenience method: when in doubt, leave it out
- avoid long (4 or more) paremeter lists, especially if they are identically typed
- for parameter types, favor interfaces over classes
- prefer 2-element enum types to boolean parameters
41. Use overloading judiciously - the choice of which overloaded method to invoke is made at compile time and is static (while selection of overridden methods is dynamic)
- avoid confusing uses of overloading: never export 2 overloaded methods with the same number of parameters
42. Use varargs judiciously- use varargs only when a call really operates on a variable-length sequence of values (otherwise use arrays)
43. Return empty arrays or collections, not nulls- there is no reason to return null from an array- or collection-valued method instead of returning an empty array or collection
44. Write doc comments for all exposed API elements- document every exported class, interface, annotation, annotation member, enum, enum constant, type parameter, constructor, method and field declaration
- use {@code} or {@literal} to eliminate the need to escape HTML meta-characters
- no 2 members or constructors in a class or interface should have the same summary description
45. Minimize the scope of local variables- declare a local variable where it is first used
- nearly every local variable should contain an initializer
- prefer for loops to while loops
- keep methods small and focused
46. Prefer for-each loops to traditional for loops- cannot use a for-each loop for filtering, transforming or parallel iteration
47. Know and use the libraries 48. Avoid float and double if exact answers are required- use BigDecimal, int (9 digits or less) or long (18 digits or less) for monetary calculations
49. Prefer primitive types to boxed primitives - applying the == operator to boxed primitives is almost always wrong
- when you mix primitives and boxed primitives in a single operation, the boxed primitive is auto-unboxed
- auto-boxing reduces the verbosity but not the danger of using boxed primitives
- unboxing can throw NullPointerException
50. Avoid strings where other types are more appropriate- strings are poos substitutes for other value types, enum types, aggregate types or capabilities
51. Beware the performance of string concatenation - using the string concatenation operator repeatedly to concatenate n strings requires time quadratic in n
- to achieve acceptable performance, use StringBuilder in place of a String
52. Refer to objects by their interfaces - if appropriate interface types exist, then parameters, return values, variables and fields should all be declared using interface types
- if you get into the habit of using interfaces as types, your program will be much more flexible
- it is entirely appropriate to refer to an object by a class rather than an interface if no appropriate interface exists
53. Prefer interfaces to reflection- object should not be accessed reflectively in normal applications at runtime
- create interfaces reflectively and access them normally via their interface or superclass
54. Use native methods judiciously- it is rarely advisable to use native methods for improved performance
55. Optimize judiciously - strive to write good programs rather than fast ones
- strive to avoid design decisions that limit performance
- consider the performance consequences of your API design decisions
- it is a very bad idea to warp an API to achieve good performance
- measure performance before and after each attempted optimization
56. Adhere to generally accepted naming conventions57. Use exceptions only for exceptional conditions- never use exceptions for ordinary control flow
- don't force your API's clients to use exceptions for ordinary control flow
58. Use checked exceptions for recoverable conditions and runtime exceptions for programming errors- use checked exceptions for conditions from which the caller can reasonably be expected to recover
- use runtime exceptions to indicate programming errors
- don't implement Error subclasses
59. Avoid unnecessary use of checked exceptions60. Favor the use of standard exceptions- parameter values: IllegalArgumentException, NullPointerException, IndexOutOfBoundsException
- IllegalStateException
- UnsupportedOperationException
61. Throw exceptions appropriate to the abstraction- higher layers should catch lower-level exceptions and in their place throw exceptions that can be explained in terms of the higher-level abstraction
- if possible, deal with lower-level exceptions rather than translating them
62. Document all exceptions thrown by each method- declare checked exceptions individually using the throws keyword and document them
- also document each unchecked exception that a method can throw, but do not use the throws keyword
63. Include failure-capture information in detail messages- the detail message of an exception should contain the values of all parameters and fields that contributed to the exception
64. Strive for failure atomicity- a failed method invocation should leave the object in the state that it was in prior to the invocation
65. Don't ignore exceptions- an empty catch block should contain a comment explaining why it is appropriate to ignore the exception
66. Synchronize access to shared mutable data- synchronization is required for reliable communication between threads as well as for mutual exclusion
- do not use Thread.stop
- synchronization has no effect unless both read and write operations are synchronized
- confine mutable data to a single thread
- when multiple threads share mutable data, each thread that reads or writes the data must perform synchronization
67. Avoid excessive synchronization- never cede control to the client within a synchronized method or block
- do as little work as possible inside synchronized regions
68. Prefer executors and tasks to threads- the key abstraction is no longer Thread - it is the unit of work (task) which is executed through an executor service
69. Prefer concurrency utilities to wait and notify- given the difficulty of using wait and notify correctly, you should use the higher-level concurrency utilities instead
- it is impossible to exclude concurrent activity from a concurrent collection; locking it will have no effect
- use ConcurrentHashMap in preference to Collections.synchronizedMap or Hashtable
- always use System.nanoTime in preference to System.currentTimeMillis
- always use the wait loop idiom: never invoke the wait method outside of a loop
70. Document thread safety- the synchronized modifier in a method declaration is an implementation detail, not a part of its exported API
- a class must clearly document what level of thread safety it supports: immutable, unconditionally thread-safe, conditionally thread-safe, not thread-safe, thread-hostile
71. Use lazy initialization judiciously- under most circumstances, normal initialization is preferable to lazy initialization
- for static fields use the lazy initialization holder class idiom
- for instance fields use the double-check idiom
72. Don't depend on the thread scheduler- every program that relies on the thread scheduler for correctness or performance is likely to be nonportable
- threads should not run if they aren't doing useful work
- don't use Thread.yield - it has no testable semantics
- thread priorities are non-portable
73. Avoid thread groups- thread groups are obsolete
74. Implement Serializable judiciously- implementing Serializable decreases the flexibility to change a class' implementation once it has been released
- increases the likelihood of bugs and security holes
- increases the testing burden associated with releasing a new version of the class
- classes designed for inheritance should rarely implement Serializable, and interfaces should rarely extend it
- consider providing a parameterless constructor on non-serializable classes designed for inheritance
- inner classes should not implement Serializable: the default serialized form of an inner class is illdefined
75. Consider using a custom serialized form - do not accept the default serialized form without thought
- the default serialized form is likely to be appropriate if an object's physical representation is identical to its logical content
- even if you decide that the default serialized form is appropriate, you often must provide a readObject method to ensure invariants and security
- before deciding to make a field non-transient, convince yourself that its value is part of the logical state of the object
- appropriately synchronize object serialization (writeObject)
- always declare an explicit serialVersionUID
76. Write readObject methods defensively- when an object is deserialized, defensively copy any field containing an object reference that a client must not possess
- do not use the writeUnshared and readUnshared methods
77. For instance control, prefer enum types to readResolve- if you depend on readResolve for instance control, all instance fields with object reference types must be declared transient
- the accessibility of readResolve is significant
78. Consider serialization proxies instead of serialized instances- whenever you find yourself having to write a readObject or writeObject method on a class that is not extendable by its clients
- perhaps the easiest way to robustly serialize objects with non-trivial invariants