Você está na página 1de 3

Consider static factory methods instead of constructors

they have names


can return same instance
can return sub-type
eliminate verbosity when creating parameterized type instances
! without public constructors your class cant be sub-classed
! hard to spot between other static methods

Use a Builder (pattern) when faced with many parameters


mix between the Telescoping pattern and JavaBeans pattern
Telescoping pattern (does not scale well) >> NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
JavaBeans pattern (allows inconsistent state - by using setters)
Builder can even cascade call >> NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();

Enforce the singleton property with a private constructor or an enum type

Enforce non-instantiability with a private constructor

Avoid creating unnecessary objects


! String s = new String(stringette); // dont do this!
String s = stringette // the object will be reused - guaranteed
use provided static fatory methods to avoid re-creating objects (e.g. Boolean.valueOf(String) instead of Boolean(String))
use a static initializer if a certain part will be reused (e.g. Calendar example)
avoid autoboxing (use primitives whenever possible)

Eliminate obsolete object references


use null to accomplish this (e.g. the Stack implemented with an Array example > weak references http://bit.ly/weak-references-java)
caches could be a memory leak source (use WeakHashMap)
listeners and callbacks as a source of memory leaks
use a heap profiler to aid finding memory leaks

Avoid finalizers
Finalizers are unpredictable, often dangerous, and generally unnecessary
try-catch block is used in Java to de-allocate resources - only if needed
can take a arbitrarily amount of time to execute the finalizer - dont do anything time-critical (e.g. closing file descriptors)
finalizer thread can have lower priority and may delay object destruction - JVM dependent
never depend on finalizers to store persistent states (they may not be executed at all)
no errors and no warnings thrown in finalizers -> corrupt state
severe penalty of performance
use it as a safety net and log a warning
FileInputStream, FileOutputStream, Connection, Timer - have this as a safety net
use to dispose of native peers (objects)
use a finalizer Guardian if your class is non-final and call the super.finalize() to make sure the subclass doesnt forget to call it

Obey the general contract when overriding equals(Object o) - use @Override annotation to avoid overloading the method instead (common mistake)
reflexive x.equals(s) = = true
transitive x.equals(y) => y.equals(z) => x.equals(z)
symmetric x.equals(y) => y.equals(x)
consistent multiple invocations of x.equals(y) should return the same result
for any non-null instance of x => x.equals(null) should return false
! there is no way to extend an instantiable class and add a value component to it and respect the equals contract
you can add a value comp. to a subclass of an abstract class without breaking the contract (Shape>Circle/Rectangle) as you cant instantiate the superclass
this is why you should favor composition over inheritance
to get this perfect:
use the == to check for the same reference
use instanceof to check if the argument is the correct type
cast the argument to the correct type (because instanceof precedes this, it will succeed)
for each significant field in the class, test if it matches the one in the other object
for primitives which are not float or double use == directly
for object reference fields invoke equals recursively
for float or double use Float.compare, respectively Double.compare
use (field == o.field || (field != null && field.equals(o.field))) (taking into account the possibility of the field containing null legitimately)
always override hashCode when overriding equals
Always override hashCode when overriding equals
use each significant field you used when overwrote equals
assuming that result is the value returned by your hash function:
start by storing some non-zero constant value (e.g. result = 17)
compute an int hashCode c for each significant field f
if field is boolean compute (f ? 1: 0)
if field is byte, char, short or int do (int) f
if field is long do (int)(f^(f>>>32))
if field is float do Float.computeToIntBits(f)
if field is double do Double.computeToLongBits(f) and do the long computation mentioned above
If the field is an object reference and this classs equals method compares the field by recursively invoking equals, recursively invoke hashCode
on the field. If a more complex comparison is required, compute a canonical representation for this field and invoke hashCode on the canonical
representation. If the value of the field is null, return 0 (or some other constant, but 0 is traditional)
If the field is an array, treat it as if each element were a separate field. That is, compute a hash code for each significant element by applying
these rules recursively, and combine these values per step 2.b. If every element in an array field is significant, you can use one of the
Arrays.hashCode methods added in release 1.5
Combine the hash code c computed in step 2.a into result as follows: result = 31 * result + c;
When you are finished writing the hashCode method, ask yourself whether equal instances have equal hash codes. Write unit tests to verify your
intuition! If equal instances have un-equal hash codes, figure out why and fix the problem

Você também pode gostar