Java bestpractice common methods

100
Best Practices with Best Practices with Java Common Object Methods Java Common Object Methods Ulrik Hørlyk Hjort Ulrik Hørlyk Hjort BestPractice Consulting & Advising 2010 BestPractice Consulting & Advising 2010 Kaiserslautern 06.07.2010 Kaiserslautern 06.07.2010

description

Java bestpractice common methods

Transcript of Java bestpractice common methods

Page 1: Java bestpractice common methods

Best Practices withBest Practices with

Java Common Object MethodsJava Common Object Methods

Ulrik Hørlyk HjortUlrik Hørlyk HjortBestPractice Consulting & Advising 2010BestPractice Consulting & Advising 2010

Kaiserslautern 06.07.2010Kaiserslautern 06.07.2010

Page 2: Java bestpractice common methods

Java Common Object MethodsJava Common Object Methods►IntroIntro

►equalsequals method method

►hashCodehashCode method method

►toStringtoString method method

►CloneableCloneable interface and interface and cloneclone method method

►ComparableComparable interface and interface and compareTocompareTo method method

Page 3: Java bestpractice common methods

Objects And Nonfinal methodsObjects And Nonfinal methods► Java objects are concrete classes primarily Java objects are concrete classes primarily

designed for extensiondesigned for extension

►The nonfinal methods:The nonfinal methods:■ equals, hashCode, toString, clone, finalizeequals, hashCode, toString, clone, finalize

all have explicit general contracts because they are all have explicit general contracts because they are designed to be overriddendesigned to be overridden

►Comparable.compareTo is not an Object method but Comparable.compareTo is not an Object method but has a similar character has a similar character

Page 4: Java bestpractice common methods

Common Object methodsCommon Object methods

The equals methodThe equals method

Page 5: Java bestpractice common methods

The equals methods contractThe equals methods contract►The The equalsequals method for the class method for the class ObjectObject implements implements

the most discriminating possible equivalence the most discriminating possible equivalence relations on objectsrelations on objects

► The contract says:The contract says:■ For any reference values For any reference values xx and and yy, the , the equalequal method method

returns true returns true if and only ifif and only if xx and and yy refer to the same refer to the same object: object: x==yx==y has the value has the value truetrue

public boolean equals(Object obj) { return (this == obj); }

Page 6: Java bestpractice common methods

equals methodequals method►When to override When to override Object.equalsObject.equals ? ?

■ When a class has a notion of logical equality that differs When a class has a notion of logical equality that differs from mere object identityfrom mere object identity

■ A superclass has not already overriden the A superclass has not already overriden the equalsequals methodmethod

■ Generally the case for Generally the case for value classesvalue classes such as Integer and such as Integer and DateDateInteger a = new Integer(1);Integer b = new Integer(1);

a.equals(b) evaluates to true a == b evaluates to false

Page 7: Java bestpractice common methods

equals methodequals method►Value classes that do not requireValue classes that do not require equals equals to be to be

overriden are instance controlled classes like:overriden are instance controlled classes like:■ Singleton classesSingleton classes■ Noninstantiable classesNoninstantiable classes

Page 8: Java bestpractice common methods

equals methodequals method►An overriden equals method must adhere to the An overriden equals method must adhere to the

general contract and implement the following general contract and implement the following equivalence relation for any non-null reference:equivalence relation for any non-null reference:■ Reflexivity: Reflexivity: x.equals(x)x.equals(x) is true is true■ Symmetry: Symmetry: x.equals(y)x.equals(y) is true => is true => y.equals(x) y.equals(x) is trueis true ■ Transitivity:Transitivity: x.equals(y) x.equals(y) is true and is true and y.equals(z)y.equals(z) is true => is true =>

x.equals(z)x.equals(z) is true is true■ Consistency: Multiple invocations of Consistency: Multiple invocations of x.equals(y)x.equals(y)

consistently returns true or falseconsistently returns true or false■ x.equals(null) always returns falsex.equals(null) always returns false

Page 9: Java bestpractice common methods

equals method: Reflexivityequals method: Reflexivity►An object must be equal to itselfAn object must be equal to itself

►Hard to violate unintentionallyHard to violate unintentionally

Page 10: Java bestpractice common methods

equals method: Symmetry equals method: Symmetry ►Two objects must agree on whether they are equalTwo objects must agree on whether they are equal

►Very easy to violate unintentionallyVery easy to violate unintentionally

►Consider the following class and try to spot how the Consider the following class and try to spot how the symmetry is violated:symmetry is violated:

Page 11: Java bestpractice common methods

equals symmetry violationequals symmetry violationpublic final class CaseInsensitiveString { private final String s;

public CaseInsensitiveString(String s) { if (s == null) throw new NullPointerException(); this.s = s; }

@Override public boolean equals(Object o) { if (o instanceof CaseInsensitiveString) return s.equalsIgnoreCase( ((CaseInsensitiveString) o).s); if (o instanceof String) return s.equalsIgnoreCase((String) o); return false; }}

Page 12: Java bestpractice common methods

equals symmetry violationequals symmetry violation►The symmetry is violated by the one way The symmetry is violated by the one way

interoperability:interoperability:

►Consider the following:Consider the following:

if (o instanceof String) return s.equalsIgnoreCase((String) o);

CaseInsensitiveString cis = new CaseInsensitiveString("Java");

String s = "java";

Page 13: Java bestpractice common methods

equals symmetry violationequals symmetry violation►cis.equals(s)cis.equals(s) returns true as expected since the returns true as expected since the

equalsequals method in CaseInsensitiveString knows about method in CaseInsensitiveString knows about ordinary stringsordinary strings

►s.equals(cis)s.equals(cis) returns false since the returns false since the equals equals method method in in StringString is oblivious to case insensitive strings is oblivious to case insensitive strings

►Symmetry violation!Symmetry violation!

►To fix the problem remove the attempt to To fix the problem remove the attempt to interoperate with interoperate with StringString from the from the equalsequals method: method:

Page 14: Java bestpractice common methods

equals symmetry violation solvedequals symmetry violation solvedpublic final class CaseInsensitiveString { private final String s;

public CaseInsensitiveString(String s) { if (s == null) throw new NullPointerException(); this.s = s; }

@Override public boolean equals(Object o) { return o instanceof CaseInsensitiveString && ((CaseInsensitiveString) o).s.equalsIgnoreCase(s); }

}

Page 15: Java bestpractice common methods

Execise 1Execise 1►Suppose you put a case insensitive string into a Suppose you put a case insensitive string into a

collection with the symmetry violationcollection with the symmetry violation equals equals method above:method above:

►What does What does list.contains(s)list.contains(s) returns? returns?

List<CaseInsensitiveString> list = new ArrayList<CaseInsensitiveString>();list.add(cis);

Page 16: Java bestpractice common methods

Execise 1 AnswerExecise 1 Answer►The answer is undefined. It can returns true, false The answer is undefined. It can returns true, false

or throw a runtime exception. It depends on the or throw a runtime exception. It depends on the current Java implementationcurrent Java implementation

►Once you have violated theOnce you have violated the equals equals contract, you contract, you simply do not know how other objects wil behave simply do not know how other objects wil behave when confronted with your objectwhen confronted with your object

Page 17: Java bestpractice common methods

equals symmetry and inheritanceequals symmetry and inheritance►Another way the symmetry often is violated is when Another way the symmetry often is violated is when

adding an aspect by extending an instantiable classadding an aspect by extending an instantiable class

►Consider:Consider:

public class Point { private final int x, y; public Point(int x, int y) { this.x = x; this.y = y; }

@Override public boolean equals(Object o) { if (!(o instanceof Point)) return false; Point p = (Point)o; return p.x == x && p.y == y; }}

Page 18: Java bestpractice common methods

equals symmetry and inheritanceequals symmetry and inheritance►Now the class is extened with the notion of color to Now the class is extened with the notion of color to

a point:a point:

public class ColorPoint extends Point { private final Color color;

public ColorPoint(int x, int y, Color color) { super(x, y); this.color = color; }}

Page 19: Java bestpractice common methods

equals symmetry and inheritanceequals symmetry and inheritance►The The ColorPointColorPoint class class equalsequals method is inherited from method is inherited from

PointPoint and the color information is ignored and the color information is ignored

►Not a contract violation but not acceptable, we need Not a contract violation but not acceptable, we need an an equalsequals method for color as well method for color as well

►An obvious solution seems to be:An obvious solution seems to be:@Override public boolean equals(Object o) { if (!(o instanceof ColorPoint)) return false; return super.equals(o) && ((ColorPoint) o).color == color;}

Page 20: Java bestpractice common methods

equals symmetry and inheritanceequals symmetry and inheritance►Do the symmetry hold?Do the symmetry hold?

►No! Consider:No! Consider:

►p.equals(cp)p.equals(cp) returns true and returns true and cp.equals(p)cp.equals(p) returns returns falsefalse

►To avoid violating the symmetry we could ignore To avoid violating the symmetry we could ignore color in mixed comparisons:color in mixed comparisons:

Point p = new Point(1, 2); ColorPoint cp = new ColorPoint(1, 2, Color.BLUE);

Page 21: Java bestpractice common methods

equals symmetry and inheritanceequals symmetry and inheritance

►This approach provide symmetryThis approach provide symmetry

►But what about transitivity?But what about transitivity?

@Override public boolean equals(Object o) { if (!(o instanceof Point)) return false;

if (!(o instanceof ColorPoint)) return o.equals(this);

return super.equals(o) && ((ColorPoint)o).color == color;}

Page 22: Java bestpractice common methods

equals method transitivity equals method transitivity ►We recall:We recall:

■ Transitivity:Transitivity: x.equals(y) x.equals(y) is true and is true and y.equals(z)y.equals(z) is true => is true => x.equals(z)x.equals(z) is true is true

►And look at:And look at:ColorPoint p1 = new ColorPoint(1, 2, Color.BLUE);Point p2 = new Point(1, 2);ColorPoint p3 = new ColorPoint(1, 2, Color.RED);

Page 23: Java bestpractice common methods

equals method transitivity equals method transitivity ►p1.equals(p2) and p2.equals(p3) returns truep1.equals(p2) and p2.equals(p3) returns true

►p1.equals(p3) returns falsep1.equals(p3) returns false

►The transitivity is violatedThe transitivity is violated

►As we see there is a fundamental problem of As we see there is a fundamental problem of equivalence relations in OO languagesequivalence relations in OO languages

►It is not posible to extend an instantiable class and It is not posible to extend an instantiable class and add a value component while preserving theadd a value component while preserving the equals equals contract! contract!

Page 24: Java bestpractice common methods

equals method transitivity equals method transitivity ►The solution: Favor composition over inheritanceThe solution: Favor composition over inheritance

public class ColorPoint { private final Point point; private final Color color;

public ColorPoint(int x, int y, Color color) { if (color == null) throw new NullPointerException(); point = new Point(x, y); this.color = color; }

@Override public boolean equals(Object o) { if (!(o instanceof ColorPoint)) return false; ColorPoint cp = (ColorPoint) o; return cp.point.equals(point) && cp.color.equals(color); }}

Page 25: Java bestpractice common methods

Be Careful!Be Careful!►Some classes in the Java platform libraries do Some classes in the Java platform libraries do

extend an instantiable classes and add value extend an instantiable classes and add value components – and violate the symmetry!components – and violate the symmetry!

►Example: Example: java.sql.Timestampjava.sql.Timestamp extends extends java.util.Datejava.util.Date and adds a nanoseconds fieldand adds a nanoseconds field

►Do not mix the Do not mix the TimestampTimestamp and and DateDate objects or use objects or use them in the same collectionthem in the same collection

►Generally always be careful mixing different objects Generally always be careful mixing different objects or use them in same collections or use them in same collections

Page 26: Java bestpractice common methods

NoteNote►If you need to add a value component to a subclass If you need to add a value component to a subclass

in a safe way add it to an abstract classin a safe way add it to an abstract class

►As long as it is impossible to create a superclass As long as it is impossible to create a superclass instance directly the equal contract cannot be instance directly the equal contract cannot be violatedviolated

Page 27: Java bestpractice common methods

equals method Consistencyequals method Consistency►Recall: Multiple invocations of Recall: Multiple invocations of x.equals(y)x.equals(y)

consistently returns true or falseconsistently returns true or false

►If two objects are equal the remain equal for all If two objects are equal the remain equal for all time unless one or both are modifiedtime unless one or both are modified

►Mutable objects can be equal to different objects at Mutable objects can be equal to different objects at different times – immutable cannotdifferent times – immutable cannot

►For immutable objects make sure that theFor immutable objects make sure that the equals equals method enforces the restriction that equal objects method enforces the restriction that equal objects remain equal and unequal objects remain unequal remain equal and unequal objects remain unequal for all time for all time

Page 28: Java bestpractice common methods

equals method Consistencyequals method Consistency►Immutable class or not: Do not write an equals Immutable class or not: Do not write an equals

method that depends on unreliable resourcesmethod that depends on unreliable resources

►Example: Example: The java.net.URLThe java.net.URL equalsequals method relies on method relies on comparison of the IP addresses of the host comparison of the IP addresses of the host associated with the URLsassociated with the URLs

►Translating a host mane to an IP address can Translating a host mane to an IP address can require network access, and it is not guaranteed to require network access, and it is not guaranteed to yield the same result over timeyield the same result over time

►This can cause (and has caused) the URL This can cause (and has caused) the URL equalsequals method to violate the method to violate the equalsequals contract contract

Page 29: Java bestpractice common methods

Object not equal to Object not equal to nullnull►The The equalsequals method always has to return false on method always has to return false on

x.equals(null)x.equals(null)

►The The equalsequals method may NOT throw a method may NOT throw a NullPointerExceptionNullPointerException

► Often the guard against this is done with an explicit Often the guard against this is done with an explicit nullnull test: test:@Override public boolean equals(Object o) { if (o == null) return false}

Page 30: Java bestpractice common methods

Object not equal to Object not equal to nullnull►The explicit The explicit nullnull test is not necessary test is not necessary

►To make sure that the argument have the To make sure that the argument have the approipriate type for the equality test, theapproipriate type for the equality test, the equals equals method must invorke the method must invorke the instanceofinstanceof operator to operator to check for the correct typecheck for the correct type

►The The instanceofinstanceof operator is specified to return operator is specified to return false false if if the first operand is null regardless of the second the first operand is null regardless of the second arument type arument type

Page 31: Java bestpractice common methods

Object not equal to Object not equal to nullnull►The The nullnull object check is therefore done as a part of object check is therefore done as a part of

the object type check and cast:the object type check and cast:@Override public boolean equals(Object o) { if (!(o instanceof MyType)) return false; MyType mt = (MyType) o;}

Page 32: Java bestpractice common methods

equalsequals Summary Summary►Overriding Overriding equalsequals is not an easy task and there are is not an easy task and there are

many ways to get into problems. So when can many ways to get into problems. So when can overriding be avoided?overriding be avoided?■ When each instance of the class is inherently uniqueWhen each instance of the class is inherently unique■ When the class do not need an logical equality testWhen the class do not need an logical equality test■ When a super class already has done the overriding in an When a super class already has done the overriding in an

appropriate way for our classappropriate way for our class■ When the class is private or package private and the When the class is private or package private and the

equal method never will be invorked equal method never will be invorked

Page 33: Java bestpractice common methods

Execise 2Execise 2►Are all 4 situations below safe ?Are all 4 situations below safe ?

■ When each instance of the class is inherently uniqueWhen each instance of the class is inherently unique■ When the class do not need an logical equality testWhen the class do not need an logical equality test■ When a super class already has done the overriding in an When a super class already has done the overriding in an

appropriate way for our classappropriate way for our class■ When the class is private or package private and the When the class is private or package private and the

equal method never will be invorked equal method never will be invorked

Page 34: Java bestpractice common methods

Execise 2 AnswerExecise 2 Answer►Not the last one. It is best practice to override the Not the last one. It is best practice to override the

equalsequals method in private and package private method in private and package private classes even you are certian it is never used.classes even you are certian it is never used.

►In case the equals method is accidentally invorked:In case the equals method is accidentally invorked:

@Override public boolean equals(Object o) { throw new AssertionError();}

Page 35: Java bestpractice common methods

How to writing a good How to writing a good equalsequals method 1method 1

►Use the Use the ==== operator to check if the argument is a operator to check if the argument is a reference to the objectreference to the object

►If so, return true. If so, return true.

►This is a performance optimization to avoid This is a performance optimization to avoid potentially expensive comparisonspotentially expensive comparisons

Page 36: Java bestpractice common methods

How to writing a good How to writing a good equalsequals method 2method 2

►Use the Use the instanceofinstanceof operator to check if the operator to check if the argument has the correct typeargument has the correct type

►if not, return falseif not, return false

►Typically, the correct type is the class containing the Typically, the correct type is the class containing the equalsequals method method

►Occasionally, it is a interface implemented by the Occasionally, it is a interface implemented by the class (Like collection interfaces as class (Like collection interfaces as Set, List, MapSet, List, Map))

Page 37: Java bestpractice common methods

How to writing a good How to writing a good equalsequals method 3method 3

►Cast the argument to the correct typeCast the argument to the correct type

►Beacuse the Beacuse the instanceofinstanceof test succeed this is test succeed this is guaranteed to succeedguaranteed to succeed

Page 38: Java bestpractice common methods

How to writing a good How to writing a good equalsequals method 4method 4

►For each significant field in the class, check if the For each significant field in the class, check if the field of the argument matches the corresponding field of the argument matches the corresponding field of the objectfield of the object

►If all test succeed, return If all test succeed, return truetrue otherwise return otherwise return falsefalse►For fields whoose type is notFor fields whoose type is not float float or or doubledouble use the use the

==== operator for comparions operator for comparions

►For For floatfloat use use Float.compareFloat.compare

►For For doubledouble use use Double.compareDouble.compare

Page 39: Java bestpractice common methods

How to writing a good How to writing a good equalsequals method 4 (Cont.)method 4 (Cont.)

►For array elements apply these guidelines to each For array elements apply these guidelines to each significant element. If all elements are significant significant element. If all elements are significant use one of the use one of the Array.equalsArray.equals methods methods

►For object reference fields invorke the equals For object reference fields invorke the equals methods recursivelymethods recursively

►Some object references may legitimately contain Some object references may legitimately contain nullnull

►To avoid a To avoid a nullPointerExceptionnullPointerException compare such fields compare such fields as: as:

Page 40: Java bestpractice common methods

How to writing a good How to writing a good equalsequals method 4 (Cont.)method 4 (Cont.)

►Some field comparisons are complex and expensive Some field comparisons are complex and expensive (e.g as (e.g as CaseInsensitiveStringCaseInsensitiveString). Consider to store ). Consider to store such fields on a cannoncical form.such fields on a cannoncical form.

►For best performance compare fields first that are For best performance compare fields first that are more likely to differ more likely to differ

(fi eld == null ? o.fi eld == null : fi eld.equals(o.fi eld))

Page 41: Java bestpractice common methods

How to writing a good How to writing a good equalsequals method 5method 5

►When you are finished writing the equals method When you are finished writing the equals method write unit tests to verify the three “tricky” properties write unit tests to verify the three “tricky” properties holds:holds:■ SymmetrySymmetry■ TransitivityTransitivity■ ConsistencyConsistency

Page 42: Java bestpractice common methods

How to writing a good How to writing a good equalsequals method 6method 6

►Always override theAlways override the hashCode hashCode method when method when override the override the equalsequals method – We will look at that in method – We will look at that in the next sectionthe next section

Page 43: Java bestpractice common methods

Execise 3Execise 3►Explain how the following Explain how the following equalsequals method will work: method will work:

public boolean equals(MyClass o) {

}

Page 44: Java bestpractice common methods

Execise 3 AnswerExecise 3 Answer►The method does not The method does not overrideoverride the the equals equals method method

but but overloadsoverloads it! A common mistake often leading it! A common mistake often leading to hours of debugging! to hours of debugging!

►Never substitute another type for Objects in the Never substitute another type for Objects in the equals declarationequals declaration

►Can we avoid this mistake ?Can we avoid this mistake ?

►Yes! Consistent use of the @override annotation will Yes! Consistent use of the @override annotation will prevent such mistakes by giving a compiler errorprevent such mistakes by giving a compiler error

Page 45: Java bestpractice common methods

Execise 3 AnswerExecise 3 Answer►The correct overloaded equals method will therefore The correct overloaded equals method will therefore

be:be:@Override public boolean equals(Object o) {

}

Page 46: Java bestpractice common methods

Execise 4Execise 4►In the next section we will look at the hashCode In the next section we will look at the hashCode

method for the class below. But first we need to method for the class below. But first we need to write the write the equalsequals method: method:

public class HashTest { private int num; private String data;

public HashTest(int num, String data) { this.num = num;this.data = data;}

}

Page 47: Java bestpractice common methods

Execise 4 AnswerExecise 4 Answerpublic class HashTest { private int num; private String data;

public HashTest(int num, String data) { this.num = num;this.data = data;}

@override public boolean equals(Object o) {

if (o == this) return true;

if (!(o instanceof HashTest)) return false;

HashTest ht = (HashTest)o; return num == ht.num &&

(data == ht.data || (data != null && data.equals(ht.data))); } }

Page 48: Java bestpractice common methods

Common Object methodsCommon Object methods

The hashCode methodThe hashCode method

Page 49: Java bestpractice common methods

The The hashCodehashCode method method►Returns the hash code value for the object on which Returns the hash code value for the object on which

the method is invorkedthe method is invorked

►The returned hash code is an integer value used by The returned hash code is an integer value used by hashing based collections such ashashing based collections such as Hashtable Hashtable, , HashMapHashMap and and HashSetHashSet

►Must be overriden in every class whereMust be overriden in every class where equals equals is is overridenoverriden

Page 50: Java bestpractice common methods

The The hashCodehashCode contract contract►From the JavaSE6 From the JavaSE6 ObjectObject specification specification

■ Whenever it is invoked on the same object more than Whenever it is invoked on the same object more than once during an exection of an application, the hashCode once during an exection of an application, the hashCode method must consistently return the same integer, method must consistently return the same integer, provided no information used in equals comparisons on provided no information used in equals comparisons on the object is modified. This integer need not remain the object is modified. This integer need not remain consistent from one execu- tion of an application to consistent from one execu- tion of an application to another execution of the same application.another execution of the same application.

Page 51: Java bestpractice common methods

The The hashCodehashCode contract (Cont.) contract (Cont.)■ If two objects are equal according to the If two objects are equal according to the equals(Object)equals(Object)

method, then calling the method, then calling the hashCodehashCode method on each of method on each of the two objects must produce the same integer result.the two objects must produce the same integer result.

■ It is not required that if two objects are unequal It is not required that if two objects are unequal according to the according to the equals(Object) equals(Object) method, then calling the method, then calling the hashCodehashCode method on each of the two objects must method on each of the two objects must produce distinct integer results. However, the produce distinct integer results. However, the programmer should be aware that producing distinct programmer should be aware that producing distinct integer results for unequal objects may improve the integer results for unequal objects may improve the performance of hash tables.performance of hash tables.

Page 52: Java bestpractice common methods

The The hashCodehashCode method method►Two distinct instances which are logically equal Two distinct instances which are logically equal

according to the class's according to the class's equalsequals method are two method are two objects with nothing in common according to the objects with nothing in common according to the ObjectObject's 's hashCodehashCode method method

►The Object's The Object's hashCodehashCode method typically returns an method typically returns an integer value based on the objects internal addressinteger value based on the objects internal address

►Look at the following class without aLook at the following class without a hashCode hashCode method:method:

Page 53: Java bestpractice common methods

The The hashCodehashCode method methodpublic class HashTest { private int num; private String data;

public HashTest(int num, String data) { this.num = num;this.data = data;}

@override public boolean equals(Object o) {

if (o == this) return true;

if (!(o instanceof HashTest)) return false;

HashTest ht = (HashTest)o; return num == ht.num &&

(data == ht.data || (data != null && data.equals(ht.data))); } }

Page 54: Java bestpractice common methods

The The hashCodehashCode method method►Use the class with a Use the class with a HashMapHashMap::

►What do What do m.get(new HashTest(1,"foo"))m.get(new HashTest(1,"foo")) returns? returns?

►Not “bar” as expected but nullNot “bar” as expected but null

►Due to the missingDue to the missing hashCode hashCode method the to equal method the to equal instances have unequal hash codesinstances have unequal hash codes

►The calling sequence is theThe calling sequence is the hashCode hashCode method and method and then - on succes - the then - on succes - the equalsequals method method

Map<HashTest, String> m = new HashMap<HashTest, String>();m.put(new HashTest(1,"foo"), "bar");

Page 55: Java bestpractice common methods

Writing the Writing the hashCodehashCode method method►How do we write a proper and legal How do we write a proper and legal hashCodehashCode

method?method?

►What about ?What about ?

►It is legal according to the contract but useless since It is legal according to the contract but useless since every object hases to the same bucket every object hases to the same bucket

@override public int hashCode() { return 42; }

Page 56: Java bestpractice common methods

Writing a good Writing a good hashCodehashCode method method►Recall the third provision of the contract:Recall the third provision of the contract:

■ ““... the programmer should be aware that producing ... the programmer should be aware that producing distinct integer results for unequal objects may improve distinct integer results for unequal objects may improve the performance of hash tablesthe performance of hash tables.”.”

►The ideal hashCode method should distrubute any The ideal hashCode method should distrubute any resonable collection of unequal instances uniformly resonable collection of unequal instances uniformly across all possible hash valuesacross all possible hash values

►It is not possible to achieve that but Sun provide a It is not possible to achieve that but Sun provide a recipe for a fair approximation:recipe for a fair approximation:

Page 57: Java bestpractice common methods

The The hashCodehashCode method recipe method recipe►Store an arbitrary constant nonzero value in anStore an arbitrary constant nonzero value in an in int t

variable called variable called hashhash. Ex. . Ex. hash = 7hash = 7►For each fieldFor each field f f in the object which is taken into in the object which is taken into

account by the account by the equalsequals method do: method do:■ Compute an Compute an intint hash code hash code cc for the field according to the for the field according to the

type:type:► booleanboolean, compute , compute (f ? 1:0)(f ? 1:0)► byte, char, shortbyte, char, short or or intint, compute , compute (int) f(int) f► longlong, compute , compute (int) (f^(f >>> 32))(int) (f^(f >>> 32))► floatfloat, compute , compute Float.floatToIntBits(f)Float.floatToIntBits(f)

Page 58: Java bestpractice common methods

The The hashCodehashCode method recipe method recipe (Cont.)(Cont.)

► doubledouble, compute , compute Double.doubleToLongBits(f)Double.doubleToLongBits(f) and then follow and then follow the step above for hashing a long resultthe step above for hashing a long result

► If f is an object reference and this class equals method If f is an object reference and this class equals method compare compare ff by recursiverly invorking of the by recursiverly invorking of the equalsequals method then method then recursiverly invorke the recursiverly invorke the hashCodehashCode method on method on f .f . If If ff is is nullnull return return 00

► If If ff is an array, treat each significant element as a seperate is an array, treat each significant element as a seperate field and apply the relevant field rules as described above. If all field and apply the relevant field rules as described above. If all fields of the array are significant use one of the fields of the array are significant use one of the Array.hashCodeArray.hashCode methods (Java 1.5 and up)methods (Java 1.5 and up)

■ Update the hash variable with c as follows:Update the hash variable with c as follows:

hash = 31 * hash +c;hash = 31 * hash +c;

Page 59: Java bestpractice common methods

The The hashCodehashCode method recipe method recipe (Cont.)(Cont.)

►When the above recipe is done on all significant When the above recipe is done on all significant fields, return fields, return hashhash

►When done writing the When done writing the hashCodehashCode method verify method verify (read: unit test!) that all equal instances have equal (read: unit test!) that all equal instances have equal hash codeshash codes

►Important:Important: Do NOT include fields in the hash code Do NOT include fields in the hash code compution that are not used in thecompution that are not used in the equals equals comparisons! Question: Why not?comparisons! Question: Why not?

►Because it violate the second provision of the Because it violate the second provision of the contractcontract

Page 60: Java bestpractice common methods

Execise 5Execise 5

►Why is it important that the initial value ofWhy is it important that the initial value of hash hash is is not zero?not zero?

►What is the idea with the multipication in: What is the idea with the multipication in: hash = hash = 31 * hash +c; 31 * hash +c; ? ?

Page 61: Java bestpractice common methods

Execise 5Execise 5

►An nonzero value is choosen so the overall hash An nonzero value is choosen so the overall hash value will not be zero in case of the valuevalue will not be zero in case of the value hc hc computed is zerocomputed is zero

►The multiplication makes the result depend on the The multiplication makes the result depend on the order of the fields which gives a better hash code in order of the fields which gives a better hash code in case of multiple similar fields. Consider acase of multiple similar fields. Consider a hashCode hashCode method for method for String String, which will have identical hash , which will have identical hash codes for all anagram if the multipication was codes for all anagram if the multipication was omitted omitted

Page 62: Java bestpractice common methods

Execise 6Execise 6►Write the hashCode method for the class (hint: look Write the hashCode method for the class (hint: look

at the equals method in execise 4) :at the equals method in execise 4) :

public class HashTest { private int num; private String data;

}

Page 63: Java bestpractice common methods

Execise 6 AnswerExecise 6 Answerpublic class HashTest { private int num; private String data;

@override public int hashCode() { int hash = 7; hash = 31 * hash + num; hash = 31 * hash + (null == data ? 0 : data.hashCode()); return hash;

}}

Page 64: Java bestpractice common methods

The The hashCodehashCode method method►If a class is immutable consider cashing the hash If a class is immutable consider cashing the hash

code with a lazy initialialization, rather than code with a lazy initialialization, rather than recalculate it each time the hashCode method is recalculate it each time the hashCode method is invorked:invorked:

public class HashTest { private int num; private String data; private volatile int hashCode;

@override public int hashCode() { int hash = hashCode;

if (hash == 0) { hash = 31 * hash + num; hash = 31 * hash + (null == data ? 0 : data.hashCode());

hashCode = hash; }

return hash; }}

Page 65: Java bestpractice common methods

The The hashCodehashCode method method►Do notDo not exclude significant parts of an object from a exclude significant parts of an object from a

hash code computation to improve performancehash code computation to improve performance■ Question: Why not?Question: Why not?

►Do notDo not specify the exact value returned by the specify the exact value returned by the hashCode methodhashCode method■ Question: Why not?Question: Why not?

Page 66: Java bestpractice common methods

Common Object methodsCommon Object methods

The compareTo methodThe compareTo method

Page 67: Java bestpractice common methods

The The compareTocompareTo method method►The The ComparableComparable interface is a mixedin interface for interface is a mixedin interface for

objects to advertise they permit cloning objects to advertise they permit cloning

►The The compareTocompareTo method is not declared in method is not declared in Object Object but but is a sole method in theis a sole method in the java.lang.Comparable java.lang.Comparable interfaceinterface

►Similar in nature to Similar in nature to equalsequals and and hashCodehashCode methods methods

►A class who implements A class who implements ComparableComparable indicate that indicate that the instance have a natural ordering the instance have a natural ordering

Page 68: Java bestpractice common methods

The The compareTocompareTo method method►Implementing Implementing ComparableComparable allows: allows:

■ calling calling Collections.sortCollections.sort and and Collections.binarySearchCollections.binarySearch■ calling calling Arrays.sortArrays.sort and and Arrays.binarySearchArrays.binarySearch■ using objects as keys in using objects as keys in TreeMapTreeMap■ using objects as elements in using objects as elements in TreeSetTreeSet

Page 69: Java bestpractice common methods

The The compareTocompareTo method method►The following example relies on the fact thatThe following example relies on the fact that Integer Integer

implements implements ComparableComparable::

public IntegerList { public static void main(String[] args) { Integer[] iList = {4,2,2,42,16};

Set<Integer> i = new TreeSet<Integer>(); Collections.addAll(s, iList); System.out.println(i); }}

[2, 4, 16, 42]

Page 70: Java bestpractice common methods

The The compareTocompareTo method method►By implementing By implementing ComparableComparable the class is allowed to the class is allowed to

interoperate with all of the many generic algorithms interoperate with all of the many generic algorithms and collections implementations depending on this and collections implementations depending on this interfaceinterface

►Tremendous amount of power for small amount of Tremendous amount of power for small amount of effort!effort!

Page 71: Java bestpractice common methods

The The compareTocompareTo method method►The general contract forThe general contract for compareTo compareTo is similar to the is similar to the

contract for the contract for the equalsequals method: method:■ ““Compares this object with the specified object for order. Compares this object with the specified object for order.

Returns a negative integer, zero, or a positive integer as Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the this object is less than, equal to, or greater than the specified object. Throws specified object. Throws ClassCastExceptionClassCastException if the if the specified object’s type prevents it from being compared specified object’s type prevents it from being compared to this object.”to this object.”

Page 72: Java bestpractice common methods

The The compareTocompareTo method method►To allow objects to be fully sorted theTo allow objects to be fully sorted the compareTo compareTo

method needs to satisfy the following conditions:method needs to satisfy the following conditions:

■ Anticommutation: Anticommutation: x.compareTo(y)x.compareTo(y) is the opposite sign of is the opposite sign of y.compareTo(x)y.compareTo(x)

■ Exception Symmetry:Exception Symmetry: x.compareTo(y) x.compareTo(y) throws the throws the excatlyexcatly same exception as same exception as y.compareTo(x)y.compareTo(x)

Page 73: Java bestpractice common methods

The The compareTocompareTo method method■ Transitivity:Transitivity:

► if if x.compareTo(y)>0x.compareTo(y)>0 and and y.compareTo(z)>0y.compareTo(z)>0, then , then x.compareTo(z)>0x.compareTo(z)>0

► if if x.compareTo(y)<0x.compareTo(y)<0 and and y.compareTo(z)<0y.compareTo(z)<0, then , then x.compareTo(z)<0x.compareTo(z)<0

► if if x.compareTo(y)==0x.compareTo(y)==0 then then x.compareTo(z)x.compareTo(z) and and y.compareTo(z)y.compareTo(z) has the same sign has the same sign

Page 74: Java bestpractice common methods

The The compareTocompareTo method method■ equalsequals consistency: consistency:

► Highly recommended, but not requiredHighly recommended, but not required► x.compareTo(y)==0x.compareTo(y)==0, if and only if, if and only if x.equals(y) x.equals(y) ► consistency with consistency with equalsequals is required for ensuring sorted is required for ensuring sorted

collections - such as collections - such as TreeSet -TreeSet - are well-behaved. are well-behaved.

Page 75: Java bestpractice common methods

The The compareTocompareTo method method► Within a class any reasonable ordering relation will satisfy Within a class any reasonable ordering relation will satisfy

the contractthe contract

► Unlike Unlike equalsequals the the compareTocompareTo method is not required to method is not required to work across classes and is permitted to throw an work across classes and is permitted to throw an ClassCastExceptionClassCastException if to objects of different classes are if to objects of different classes are comparedcompared

► As with hashCode a violation of the contract can break As with hashCode a violation of the contract can break other classes depending on comparison like sorted other classes depending on comparison like sorted collections,collections, TreeSet, TreeMap TreeSet, TreeMap and the utility classes and the utility classes CollectionsCollections and and Arrays Arrays containing search and sort algoritmscontaining search and sort algoritms

Page 76: Java bestpractice common methods

The The compareTocompareTo method method►A consequence of the three provisions: A consequence of the three provisions:

Anticommutation, Symmetry and Transitivity is – like Anticommutation, Symmetry and Transitivity is – like equalsequals – that there is no simple way to extend an – that there is no simple way to extend an instantiable class with a new aspect while instantiable class with a new aspect while preserving the contractpreserving the contract

►If a new significant aspect need to be added to the If a new significant aspect need to be added to the class use composition instead of inheritance (as with class use composition instead of inheritance (as with equalsequals))

Page 77: Java bestpractice common methods

The The compareTocompareTo method method►Be aware if theBe aware if the compareTo compareTo method imposes an method imposes an

order inconsistent with order inconsistent with equalsequals►Sorted collections containing elements of the class Sorted collections containing elements of the class

may not obey the general contract of the may not obey the general contract of the appropriate collection interfaces –appropriate collection interfaces – Collection, Set, Collection, Set, MapMap

Page 78: Java bestpractice common methods

Example: Inconsistent Example: Inconsistent equalsequals and and compareTocompareTo methods methods

►In the following the set wil contain two elements In the following the set wil contain two elements because the equals method is used for comparison:because the equals method is used for comparison:

public class Inconsistent { public static void main(String [] args) throws IOException {

Set<BigDecimal> Hs = new HashSet<BigDecimal>(); Hs.add(new BigDecimal("42.0")); Hs.add(new BigDecimal("42.00"));

Iterator<BigDecimal> It = Hs.iterator();

while (It.hasNext()) { System.out.println(": "+It.next());}

}}

Page 79: Java bestpractice common methods

Example: Inconsistent Example: Inconsistent equalsequals and and compareTocompareTo methods methods

►In the following the set wil contain one element In the following the set wil contain one element because the compareTo method is used:because the compareTo method is used:

public class Inconsistent { public static void main(String [] args) throws IOException {

Set<BigDecimal> Ts = new TreeSet<BigDecimal>(); Ts.add(new BigDecimal("42.0")); Ts.add(new BigDecimal("42.00"));

Iterator<BigDecimal> It = Ts.iterator();

while (It.hasNext()) { System.out.println(": "+It.next());}

}}

Page 80: Java bestpractice common methods

Writing the Writing the compareTocompareTo method method►Writing theWriting the compareTo compareTo method is almost similar to method is almost similar to

writing the writing the equalsequals method method

►Type check for casting is not needed. If the Type check for casting is not needed. If the argument is not of the appropriate type thow the argument is not of the appropriate type thow the ClassCastExceptionClassCastException

►If the argument isIf the argument is null null the the compareTocompareTo method method shallshall throw a throw a NullPointerException NullPointerException (The behavior as if the (The behavior as if the argument is type casted and an attempt to access argument is type casted and an attempt to access the members is done) the members is done)

Page 81: Java bestpractice common methods

Writing the Writing the compareTocompareTo method method►Remember: The field comparisons are Remember: The field comparisons are orderorder

comparisons rather thancomparisons rather than equality equality comparisons as comparisons as for for equalsequals

Page 82: Java bestpractice common methods

Writing the Writing the compareTocompareTo method method►Various types of fields are compared as follows:Various types of fields are compared as follows:

■ numeric primitive : Use numeric primitive : Use << and and >>. . ► For For floatfloat and and doubledouble primitives use primitives use Float.compare(float, float)Float.compare(float, float)

and and Double.compare(double, double)Double.compare(double, double)..

■ boolean primitive : Use tests of the form boolean primitive : Use tests of the form (x && !y)(x && !y)■ Object references: Use Object references: Use compareTocompareTo invorked recursively invorked recursively■ Arrays: Apply the above guidelines to each elementArrays: Apply the above guidelines to each element

Page 83: Java bestpractice common methods

Writing the Writing the compareTocompareTo method method►If a field does not implement If a field does not implement ComparableComparable or a non or a non

standard ordering need to be used write or use an standard ordering need to be used write or use an explicit explicit ComparatorComparator. .

►If the class has multiple significant fields the If the class has multiple significant fields the comparison order will be critical. Start with the most comparison order will be critical. Start with the most significant field and work downsignificant field and work down

►If a comparison result is different from zero then If a comparison result is different from zero then stop the comparison and return the resultstop the comparison and return the result

►If all fields are equals, the objects are equal, return If all fields are equals, the objects are equal, return zerozero

Page 84: Java bestpractice common methods

Execise 7Execise 7►Write the Write the compareTocompareTo method for the following class: method for the following class:

public class CompareTo_Class {

private String name; private int number; private boolean isOk;

public int compareTo( CompareTo_Class cc ) { }}

Page 85: Java bestpractice common methods

Execise 7 AnswerExecise 7 Answer

public class CompareTo_Class implements Comparable<CompareTo_Class> {

private String name; private int number; private boolean isOk;

public int compareTo( CompareTo_Class cc ) { if (this.number < cc.number) return -1; if (this.number > cc.number) return 1; if (!this.isOk && cc.isOk) return -1; if (this.isOk && !cc.isOk) return 1;

int comparison = this.name.compareTo(cc.name); if ( comparison != 0 ) return comparison;

return 0; }}

Page 86: Java bestpractice common methods

Execise 7 AnswerExecise 7 Answer►Did you remember to implement theDid you remember to implement the Comparable Comparable

interface?interface?

►IMPORTANTIMPORTANT: Implementing the : Implementing the ComparableComparable interface is telling the Java type-checker and the interface is telling the Java type-checker and the runtime system, that you have provided aruntime system, that you have provided a compareTo()compareTo() method. Without that information you method. Without that information you will not be allowed to use your objects where awill not be allowed to use your objects where a ComparableComparable interface is expected even though they interface is expected even though they do have the implemented the do have the implemented the compareTocompareTo method. method.

Page 87: Java bestpractice common methods

Execise 7 AnswerExecise 7 Answer

public class CompareTo_Class implements Comparable<CompareTo_Class> {

public int compareTo( CompareTo_Class cc ) {

if ( this == cc ) return 0;

if (this.number < cc.number) return -1; if (this.number > cc.number) return 1; if (!this.isOk && cc.isOk) return -1; if (this.isOk && !cc.isOk) return 1;

int comparison = this.name.compareTo(cc.name); if ( comparison != 0 ) return comparison;

assert this.equals(cc) : "compareTo inconsistent with equals.";

return 0; }}

Page 88: Java bestpractice common methods

Execise 7 AnswerExecise 7 Answer►Doing the testDoing the test if ( this == cc ) return 0;if ( this == cc ) return 0; before before

doing any comparisions, to verify that the object is doing any comparisions, to verify that the object is not compared to it self, is a worthwhile optimization not compared to it self, is a worthwhile optimization

►If the If the compareTocompareTo method has to be method has to be equalsequals consistent add consistent add assert this.equals(cc) : "compareTo assert this.equals(cc) : "compareTo inconsistent with equals.";inconsistent with equals."; before the last return before the last return statementstatement

Page 89: Java bestpractice common methods

Execise 7 AnswerExecise 7 Answer►Since the contract does not specify the magnitude Since the contract does not specify the magnitude

of the return value from compareTo it is possible to of the return value from compareTo it is possible to improve it using that fact:improve it using that fact:

public class CompareTo_Class implements Comparable<CompareTo_Class> {

public int compareTo( CompareTo_Class cc ) {

int numberDiff = this.number – cc.number; if (numberDiff !=0) return numberDiff;... return 0; }}

Page 90: Java bestpractice common methods

Execise 7 AnswerExecise 7 Answer►But use this trick with caution! Never use it if:But use this trick with caution! Never use it if:

■ The field in question can be negativeThe field in question can be negative■ The difference between the lowest and highest possible The difference between the lowest and highest possible

field values is less than or equal to field values is less than or equal to Integer.MAX_VALUE Integer.MAX_VALUE (2^31-1) (2^31-1)

Page 91: Java bestpractice common methods

Common Object methodsCommon Object methods

The clone methodThe clone method

Page 92: Java bestpractice common methods

The The cloneclone method method► The The CloneableCloneable interface was intended as a mixedin interface was intended as a mixedin

interface for objects to advertise they permit cloninginterface for objects to advertise they permit cloning

► Problems:Problems:

■ The The CloneableCloneable interface lacks a interface lacks a cloneclone method! method! ■ ObjectObject's 's cloneclone method is protected! method is protected!

► CloneableCloneable determines the behavior of determines the behavior of ObjectObject's protected 's protected cloneclone method, returns field by field copy of the object method, returns field by field copy of the object

► If a class implements Cloneable, If a class implements Cloneable, ObjectObject's 's cloneclone method method returns a field by field copy of the object – otherwise it returns a field by field copy of the object – otherwise it throws throws CloneNotSupportedExceptionCloneNotSupportedException

Page 93: Java bestpractice common methods

The The cloneclone method method►Note: The use of an interface to modify the Note: The use of an interface to modify the

behavior of a protected super class method as behavior of a protected super class method as CloneableCloneable do is do is NOTNOT good style! Never do it! good style! Never do it! Interfaces shall only be used to say something Interfaces shall only be used to say something about what a class can do for its clients about what a class can do for its clients

Page 94: Java bestpractice common methods

The The cloneclone method methodSummary: It is very hard to implement Summary: It is very hard to implement Cloneable Cloneable right right and it is not the effort worth to try – so never use the and it is not the effort worth to try – so never use the clone clone methodmethod!!

Page 95: Java bestpractice common methods

Common Object methodsCommon Object methods

The toString methodThe toString method

Page 96: Java bestpractice common methods

The The toStringtoString method method►Provides a simple convenient mechanism for:Provides a simple convenient mechanism for:

■ Debugging classes during developmentDebugging classes during development■ LoggingLogging■ Passing error messages to exception constructors and Passing error messages to exception constructors and

assertionsassertions

►More formally More formally toStringtoString can be used to translating an can be used to translating an object into a well-defined textual form object into a well-defined textual form (toString(toString) ) and back again (and back again (valueOfvalueOf))

Page 97: Java bestpractice common methods

The The toStringtoString method Contract method Contract►The general The general toStringtoString contract says: contract says:

■ ““Returns a string representation of the object. In Returns a string representation of the object. In general, the toString method returns a string that general, the toString method returns a string that "textually represents" this object. The result should be a "textually represents" this object. The result should be a concise but informative representation that is easy for a concise but informative representation that is easy for a person to read. It is recommended that all subclasses person to read. It is recommended that all subclasses override this method.”override this method.”

Page 98: Java bestpractice common methods

The The toStringtoString method method►The The toStringtoString method is not so important as the method is not so important as the

previous methodsprevious methods

►The The toStringtoString method should return all of the method should return all of the interesting information contained in the objectinteresting information contained in the object

►If the object is large or contains states that are not If the object is large or contains states that are not conducive to string representation theconducive to string representation the toString toString method should return a summarymethod should return a summary

Page 99: Java bestpractice common methods

The The toStringtoString method method►Specially for value classes consider to specify the Specially for value classes consider to specify the

format of the return valueformat of the return value■ Example: Look at the specification for the Example: Look at the specification for the

toString(double d)toString(double d) in the in the DoubleDouble class class

►If the format is specified consider to provide a If the format is specified consider to provide a matching matching StringString constructor or a static factory – like constructor or a static factory – like the the valueOfvalueOf method – to translate back to the method – to translate back to the Object from its string representationObject from its string representation■ Example: Look at the Example: Look at the valueOf(String s)valueOf(String s) method in the method in the

DoubleDouble class class

Page 100: Java bestpractice common methods

The EndThe End►