Methods Common to all Objects

Item 8: Obey the general contract when overriding equals

Entity-Typen überschreiben selten die equals()-Methode. Da sie keine Werte darstellen, ist der Vergleich des Inhalts praktisch bedeutungslos und aus diesem Grunde ist es völlig in Ordnung, wenn zwei Entity-Objekte genau dann “gleich” sind, wenn sie identisch sind.

Das ist bei Value-Typen ganz anders. Der Inhalt ist das Wesentliche des Objekte und deshalb sind zwei Value-Objekte genau dann gleich, wenn sie den gleichen Inhalt haben. In solchen Fällen muss equals() überschrieben werden, denn die Default-Implementierung ist unbrauchbar für solche Value-Typen.

Do not override equals if

  • Each instance of the class in inherently unique. This means that the logical equality does not differ from object identity.
  • You don't care whether the class provides a logical equality test.
  • A superclass has already overridden equals, and the superclass behavior is appropriate for this class.
  • The class is private or package-private, and you are certain that its equals method will never be invoked.

If you override equals, you must adhere to its contract. This means

  • Reflexive: For any non-null x → x.equals(x)
  • Symmetric: For any non-null x and y → if x.equals(y) then y.equals(x)
  • Transitive: For any non-null x, z, z → if x.equals(y) and y.equals(z) then x.equals(z)
  • Consistent: For any non-null x, z → multiple invocations of x.equals(y) consistently return true or false, provided no information used in equals on the object is modified.
  • Non-nullity: For any non-null x → x.equals(null) must return false (not throwing an exception)

Howto:

  1. Use the == operator to check if the argument is a reference to this object → If so return true
  2. Use the instanceof operator to check if the argument has the correct type → If not return false (Use the class of the method or an interface)
  3. Cast the argument to the correct type
  4. For each “significant” field in the class, check if that field of the argument matches the corresponding field of this object → If all tests succeed return true

For primitive fields use ==, for double and float use Double.compare or Float.compare, for object reference fields use the equals-method

  1. When finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent? → Write tests
  2. Always override hashCode when you override equals

Notes:
The transtivity can not be hold if an instantiable class is extended and a value component is added. This is for example the case for TimeStamp which
extends Date and adds a nanosecond field.

  String init = "Hello World !";

  StringBuffer sb1 = new StringBuffer(init);
  StringBuffer sb2 = new StringBuffer(init);
  ...
  if (sb1 == sb2) ...            // yields false
  ...
  if (sb1.equals(sb2)) ...       // yields false because StringBuffer does not override the equals method (!!!) 

AngelikaLanger has another approach as Joshua Bloch. She differs between direct subclasses of Object and other classes:

class MyClass {
   private String s;
   private int i;
   ...
   public boolean equals(Object other) {
   if (this == other)
      return true;
   if (other == null)
      return false;
   if (other.getClass() != getClass())
      return false;

   if (!(s.equals(((MyClass)other).s)))
      return false;
   if (i != ((MyClass)other).i)
      return false;
   ...
   return true;
   }
  } 
class MySubclass extends MyClass {
   private String t;
   ...
   public boolean equals(Object other) {
   if (this == other)
      return true;
   if (!super.equals(other))
      return false;

   if (!(t.equals(((MyClass)other).t)))
      return false;
   ...
   return true;
   }
  } 

Ans she says:
Es gibt zwei Möglichkeiten, den Vergleichbarkeitstest in equals() zu machen: mit Hilfe der getClass()-Methode oder mit Hilfe des instanceof-Operators.

  • Die getClass()-Technik ist robust und unproblematisch und daher zu empfehlen.
  • Die instanceof-Technik ist weit verbreitet, macht aber nur bei Klassen Sinn, die final sind.

Item 9: Always override hashCode when you override equals

Contract:

  • The hashCode invoked on the same object more than once must return the same integer, provided no information used in equals on the object is modifierd. Caution: This must only be true the same execution of an application. Therefore do not use the hashCode fer persistence.
  • If a.equals(b) –> a.hashCode() == b.hashCode()
  • It is not required (but recommended for performance reasons) that if two objects are unuequal according to the equals method, then calling the hashCode method on each of the two objects

must produce distinct integer results.

Recipe to compute a hashValue:

  1. Store some constant nonzero value, say, 17 in an int variable
  2. For each significant f in your object (taken into account by the equals method), do the following
  • if the field is a boolean, compute (f?1:0)
  • if the field is a byte, chart, short or int, compute (int) f.
  • if the field is a long compute (int) f ^ (f »> 32)
  • if the field is a long, compute Float.FloatToIntbBits(f)
  • if the field is a double, copute Double.doubleToLongBits(f) and the hash the resulting long
  • if the field is an object, compute 1)
  • if the field is an array, compute a hash code for each significant element
  1. combine the hash code c into result as follows:

result = 31 * result + c;

Item 10: Always override toString

  • Providing a good toString implementation makes your class much more pleasant to use. The toString method is automatically invoked

when an object is passed to println, printf, the string concatenation opearator, assert or printed by a debugger.

  • When practical, the toString method should return all of the interesting information contained in the object.
  • If you specify the format in the documentation, then you are stuck with it for life. Changes would not be appreciated by users of your class.

Item 11: Override clone judiciously

Contract:

  • x.clone() != x
  • x.clone().getClass() == x.getClass()
  • x.clone().equals(x)

A clones object should be equals to its original, but not depend on it. Arrays clone() method create only a swallow copy (not a deep one) and therefore does not
fulfil this condition.

Point[] pa1 = { new Point(1,1), new Point(2,2) };
Point[] pa2 = null;

try {
 pa2 = (Point[]) pa1.clone();
} catch (CloneNotSupportedException e) { ... } 
pa2[0] = new Point(-2,-2);
pa2[0].x =  2;
pa2[1].y = -2; // -> pa1[1].y != 2

Alle non-final Klassen, die Value-Type [ 2 ] repräsentieren und nicht-statische Felder haben, welche Referenzen auf veränderliche Objekte oder Arrays von veränderlichen Objekte sind, sollten eine Implementierung von clone() haben, welche super.clone() ruft und alle ihre Felder in genügender Tiefe kopiert. Diese Implementierung von clone() muss nicht einmal als public Methode angeboten werden und die non-final Klasse muss auch nicht cloneable sein. Es genügt, wenn eine korrekte Implementierung von clone() als protected Methode zur Verfügung steht, damit Subklassen ihrerseits cloneable werden können und ihre clone()-Methode mit Hilfe der protected clone()-Methode der Superklasse implementieren können.

In der Implementierung von clone() vermeide man den Aufruf von non-final Methoden auf dem halbfertigen Klon.

Es gibt eine einzige Situation, in der ein Copy-Konstruktor als Ersatz für eine clone()-Methode vertretbar ist: bei Klassen, die als final deklariert sind. Eine final Klasse kann keine Subklassen haben; ohne Klassenhierarchie spielt Polymorphie keine Rolle und dann ist auch ein Copy-Konstruktor akzeptabel.

Item 12: Consider implementing Comparable

Contract:

public int compareTo(Object o)

Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

  • In the foregoing description, the notation sgn(expression) designates the mathematical signum function, which is defined to return one of -1, 0, or 1 according to whether the value of expression is negative, zero or positive. The implementer must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an exception.)
  • The implementer must also ensure that the relation is transitive: (x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0.
  • Finally, the implementer must ensure that x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)), for all z.
  • It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is “Note: this class has a natural ordering that is inconsistent with equals.”

Classes and interfaces

Item 13: Minimize the accessibility of classes and member

A well-designed module hides all of its implementation details, cleanly separating its API from its implementatin. This concept, known as information hiding or
encapsulation, is one of the fundamental tenets of software design. Make each class or member as inaccessible as possible. For top-level (non-nested) classes and
interfaces, there are only two possible access levels: package-private and public. If a top-level class or interface can be made package-private, it should be. By making it package-private, you make it part of the implementation rather than the exported API, and you can modify it, replace it, or eliminate it in a subsequent
release without fear of harming existing clients. If you make it public, you are obligated to support it forever to maintain compatibility.
A protected member is part of the class's API and must be supported forever. The need for protected member should be raltively rare. to facilitate testing, you may
be tempted to make a class, iinterface, or member mre accessible. This is fine up to a point. It is acceptable to make a private member of a public class package-private in order to test it, but it is not acceptable to raise the accessibiity and higher than that. Instance fields should never be public. If you do so, you give up the
ability to limit the values than can be stored in the field. Also, you give up the ability to enforce invariante involving the field. Also, you give up the ability to
take any action when the field is modified, so classes with public mutable fields are not thread-safe!
The same advice applies to static fields, with the one exception. You can expose constants via public static final fields, assumint the constants form an integral part of the abstractio provided by the class. It is critical that these fields contain either primitive values or references to immutable objects. It is wrong for a class to have a public static final array field, or an accessor that return such a fields. If a class has such a field, clients will be able to modif the contents of the array.
You can solve this issue the following way:

private static final Thing[] PRIVATE_VALUES = {}
public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES);

public static final Thing[] values() {
  return PRIVATE_VALUES.clone();
}

Item 14: In public classes, use accessor methods, not public fields

Public classes should never expose mutable fields (you can't change the representation without changing the API, you can't enfore
invariante, and you can't take auxiliary action when a field is accessed). It is less harmful, though still questionable, for public
classes to exposte immutable fields (invariants are still possible). It is however, sometimes desirable for package-private or private
nested classes to exposte fields, whether mutable or immutable. This approach generates less visual clutter than the accessor-method approach,
both in the class definition and in the client code that uses it.

Item 15: Minimize mutability

How to make an object immutable:

  1. Don't provide any methods that modify the ojects's state (known as mutators).
  2. Ensure that the class can't be extended.
  3. Make all fields final
  4. Make all fields private
  5. Ensure exclusive access to any mutable components.

Advantages of immutable objects:

  • They are simple. They can be only in exactly one state, the state in which it was created. If you make sure that all constructors establish class invariants,

then it is guaranteed that these invariants will remain truee for all time.

  • Immutable objects are inherently thread-safe; they require no synchronization.
  • Immutable objects can be shared freely. Immutable classes should take advantage of this by encouraging clients to reuse existing instances wherever possible.

It is not necessary to create defensive copies of them. Therefore, you need not and should not provide a clone method or copy constructor.

  • Not only can you share immutable objects, but you can share their internals (example BigInteger).
  • Immutable objects make gread building block for other objects. They do a great job for map keys and set elements: you don't have to worry about their values changing once they're in the map or set.

Disadvantage:

  • Immutable classes require a separate object for each distinct value. Creating these objects can be costly. The performance problem is magnified

if you perform a multistep operation that generates a new object at every step (“a” + “b” + “c”). A solution is to create a package-private mutable “companion
class” (BigInteger uses this approach). If you do not know exactly which operations clients will want to perform on you immutable class, it is best to provide
a public mutable class. Think of StringBuilder (String)

Item 16: Favor composition over inheritance (also known as Decorator Pattern)

Inheritance violates encapsulation. A subclass depends on the implementation details of its superclass for its proper function. The superclass's implementation
may change from release to release, and if it does, the subclass may break, even though its code has not been touched. As a consequence, a subclass may break,
even though its code has not been touched. As a consequence, a subclass must evolve in tandem with its superclass, unless the superclass's authors have designed and
documented it specially for the purpose of being extendend. It is safe to use inheritance withing a package, where the sublcass and the superclass are unter the control
of the same programmers. A class B should extend a class A only if an “is-a” relationship exists between the two classes. So a Stack should not extend from Vector, and Properties should not extend from HashTable.

public class InstrumentedSet<E> extends ForwardingSet<E> {
  private int addCount = 0;
  
  public InstrumentedSet(Set<E> s) {
    super(s);
  }
  
  @Override public boolean add(E e) {
    addCount++;
    return super.add(e);
  }
  
  @Override public boolean addAdd(Collection<? extends E> c) {
    addCount += c.size();
    return super.addAll();
  }
  public int getAddCount() {
    return addCount;
  }
}

public class ForwardingSet<E> implements Set<E> {
  private final Set<E> s;
  public ForwardingSet(Set<E> s) {this.s = s;}
  public void clear() {s.clear()}
  public int size() {return s.size()}
  ...
  ...
  ...
}

Note: The forwarding could also be implemented in the InstrumentedSet directly. This is appropriate
if you know that there will be no further Concrete Decorators.

Item 17: Design and document for inheritance or else prohibit it

Document the behavior of overridable methods. Mention which other methods are invoked, so that a subclass know the behavior of its superclass.
Expose as few protected members as possible, but not too few, as a missing protected member can render c class practically unusable for inheritance.
The only way to test a class designed for inheritance is to write subclasses.

Constructors must not invoke overridable methods.

 public class Super {
   public Super() {
     overrideMe();
   }
 }
 public void overrideMe() {
 }
}

public final class Sub extends Super {
  private final Date date;
  
  Sub() {
    date = new Date();
  }
  @Override public void overrideMe() {
    Sub sub = new Sub();
    sub.overrideMe();
  }
}
Result: null, date! -> a final field has two states, this is bad!

How to prohibit subclassing:

  • Make the class final
  • Make all constructors private or package-private and add public static factories.
  • Avoid to self-use overridable methods. If you do so, you'll create a class that is reasonable safe to subclass. Overriding a method will never affect the behavior of any other method. You can to this, by moving the body of each overridable method to a private “helper method” and have each overridable method invoke its private helper method. Then replace each self-use of an overridable method with a direct invocation of the overridable method's private helper method.

Generics

Item 23: Don't use raw types in new code

Item 57: Use exceptions only for exceptional conditionts

Do not do this:

try { 
  int i = 0;
  while(true) 
    range[i++].climb();
} catch(ArrayIndexOutOfBoundsException e) {
}

Write and use state-testing methods:

for(Iterator<Foo> i = collection.iterator(); i.hasNext();) {
  Foo foo = i.next();
}

An alternative to providing a separate state-testing method is to have the state-dependant method return a distinguished value such as null (usefull if an object is to
be accesses concurrently without external synchronization).

Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors

Runtime exceptions and errors are throwables that needn't, and generally shouldn't be caught. The great majority of runtime exceptions
indicate precondition violations. There is a strong convention that errors are reserved for use by the JVM.

Item 59: Avoid unnecessary use of checked exceptions

Checked exceptions are justified if
- If the exceptional condition cannot be prevented by proper use of the API - And the programmer using the API can take some useful action once confronted with the exception.

How to change a checked exception into an unchecked

try {
  obj.action(args);
} catch(TheCheckedException e) {
  //Handle
}

if(obj.actionPermitted(args)) {
  obj.action(args);
} else {
  //Handle
}

Second solution seems no prettier than the former, the resulting API is
indeed more flexible. In cases where the programmer knows the call will
succeed or is content to let the thread terminate if the call faills,
the refactoring also allows this simple calling sequence:
obj.action(args)

Item 60: Favor the use of standard exceptions

- IllegalArgumentException
- IllegalStateException → Object state is inappropriate for method invocation
- NullPointerException
- IndexOutOfBoundsException
- ConcurrentModificationException
- UnsupportedOperationException

If an exception fits your needs, go agead and use it, but onl if the conditions
under which you would throw it are consistent with the exception's documentation.

Item 61: Throw exceptions appropriate to the abstraction

It is disconcerting when a method throws an exception that has no apparent
connection to the task that it performs.

//Exception translation
try {
  //Use lower-level abstraction to do our bidding
} catch(LowerLevelException e) {
  throw new HigherLevelException()
}
//Exception Chaining
try {
  //Use lower-level abstraction to do our bidding
} catch(LowerLevelException cause) {
  throw new HigherLevelException(cause)
}

The best way to deal with exceptions from lower layers is to avoid them, by
ensuring that lower-level method succeed. (check validity of higher-level method's parameters before passing them on to lower layers).

The next best thing is to have the higher layer silently work around these exceptions, insulating the caller of the higher-level method from lower-level problems. (think to log the exception in this case).

If it isn't feasible to prevent or handle exceptions from lower layers, use exceptions translation, unless the lower-level method happens to guarantee that all of its exceptions are appropriate to the higher level.

Item 62: Document all exceptions thrown by each method

This is true for unchecked as well as checked exceptions, and for abstract as well as concrete methods. Provide invidual throws clauses for each checked exception and do not provide throws clasues for unchecked exceptions. If every method throws the same exception it is ok to declare the exception in the class's documentation.

Item 63: Include failure-capture information in detail messages

To capture the failure, the detail message of an exception should contain
the values of all parameters and fields that contributed to the exception.
It is, indeed, not important to include a lot of prose.
The best to do is to construct the failure-message directly in the constructor.

public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) {
 super("Lower bound: " + lowerBound + ", Upper bound: " + upperBound +
       ", Index: " + index);
 //Save failure informationn for programmatic access
  this.lowerBound = lowerBound;
  this.upperBound = upperBound;
  this.index = index;
}

Item 64: Strive for failure atomicity

A failed method invocation should leave the object in the state that it was in prior to the invocation.

Item 64: Don't ignore exceptions

Don't:

try {
...
{ catch(SomeException e) {
}
1) field==null)?0:field.hashCode(
 
wettstein/effectivejava.txt · Last modified: 2010-06-29 23:24 by frank.wettstein
 
Recent changes RSS feed Creative Commons License Powered by GNU/Linux Powered by Gentoo Powered by Apache Powered by XCache Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki