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