Practical Java
Peter Haggar

General Techniques
  1. Understand that parameters are passed by value, not by reference.
  2. Use final for constant data and constant object references.
  3. Understand that all non-static methods can be overridden by default.
  4. Choose carefully between arrays and Vectors.
  5. Prefer polymorphism to instanceof.
  6. Use instanceof only when you must.
  7. Set object references to null when they are no longer needed.
Objects and Equality
  1. Differentiate between reference and primitive types.
  2. Differentiate between == and equals.
  3. Do not rely on the default implementation of equals.
  4. Implement the equals method judiciously.
  5. Prefer getClass in equals method implementations.
  6. Call super.equals of base classes.
  7. Consider carefully instance of in equals method implementations.
  8. Follow these rules when implementing an equals method.
Exception handling
  1. Know the mechanics of exception control flow.
  2. Never ignore an exception.
  3. Never hide an exception.
  4. Consider the drawback to the throws clause.
  5. Be specific and comprehensive with the throws clause.
  6. Use finally to avoid resource leaks.
  7. Do not return from a try block.
  8. Place try/catch blocks outside of loops.
  9. Do not use exceptions for control flow.
  10. Do not use exceptions for every error condition.
  11. Throw exceptions from constructors.
  12. Return objects to a valid state before throwing an exception.
Performance
  1. Focus initially on design, data structures, and algorithms.
  2. Do not rely on compile-time code optimization.
  3. Understand runtime code optimization.
  4. Use StringBuffer, rather than String, for concatenation.
  5. Minimize the cost of object creation.
  6. Guard against unused objects.
  7. Minimize synchronization.
  8. Use stack variables whenever possible.
  9. Use static, final, and private methods to allow in lining.
  10. Initialize instance variables only once.
  11. Use primitive types for faster and smaller code.
  12. Do not use an Enumeration or an Iterator to traverse a Vector.
  13. Use System array copy for copying arrays.
  14. Prefer an array to a Vector or ArrayList.
  15. Reuse objects whenever possible.
  16. Use lazy evaluation.
  17. Optimize source code by hand.
  18. Compile to native code.
Multithreading
  1. Understand that for instance methods, synchronized locks objects, not methods or code.
  2. Distinguish between synchronized statics and synchronized instance methods.
  3. Use private data with an accessor method instead of public or protected data.
  4. Avoid unnecessary synchronization.
  5. Use synchronized or volatile when accessing shared variables.
  6. Lock all objects involved in a single operation.
  7. Acquire multiple locks in a fixed, global order to avoid deadlock.
  8. Prefer notifyAll to notify.
  9. Use spin locks for wait and notifyAll.
  10. Use wait and notifyAll instead of polling loops.
  11. Do not reassign the object reference of a locked object.
  12. Do not invoke the stop or suspend methods.
  13. Terminate threads through thread cooperation.
Classes and Interfaces
  1. Use interfaces to support multiple inheritance.
  2. Avoid method clashes in interfaces.
  3. Use abstract classes when it makes sense to provide a partial implementation.
  4. Differentiate between an interface, abstract class, and concrete class.
  5. Define and implement immutable classes judiciously.
  6. Use clone for immutable objects when passing or receiving object references to mutable objects.
  7. Use inheritance or delegation to define immutable classes.
  8. Call super.clone when implementing a clone method.
  9. Do not rely on finalize methods for non-memory resource cleanup.
  10. Use care when calling non-final methods from constructors.