@EqualsAndHashCode

Overview

Any class definition may be annotated with @EqualsAndHashCode to let lombok generate implementations of the equals(Object other) and hashCode() methods. By default, it'll use all non-static, non-transient fields, but you can exclude more fields by naming them in the optional exclude parameter to the annotation. Alternatively, you can specify exactly which fields you wish to be used by naming them in the of parameter.

By setting callSuper to true, you can include the equals and hashCode methods of your superclass in the generated methods. For hashCode, the result of super.hashCode() is included in the hash algorithm, and for equals, the generated method will return false if the super implementation thinks it is not equal to the passed in object. Be aware that not all equals implementations handle this situation properly. However, lombok-generated equals implementations do handle this situation properly, so you can safely call your superclass equals if it, too, has a lombok-generated equals method.

Setting callSuper to true when you don't extend anything (you extend java.lang.Object) is a compile-time error, because it would turn the generated equals() and hashCode() implementations into having the same behaviour as simply inheriting these methods from java.lang.Object: only the same object will be equal to each other and will have the same hashCode. Not setting callSuper to true when you extend another class generates a warning, because unless the superclass has no (equality-important) fields, lombok cannot generate an implementation for you that takes into account the fields declared by your superclasses. You'll need to write your own implementations, or rely on the callSuper chaining facility.

NEW in Lombok 0.10: Unless your class is final and extends java.lang.Object, lombok generates a canEqual method which means JPA proxies can still be equal to their base class, but subclasses that add new state don't break the equals contract. The complicated reasons for why such a method is necessary are explained in this paper: How to Write an Equality Method in Java. If all classes in a hierarchy are a mix of scala case classes and classes with lombok-generated equals methods, all equality will 'just work'. If you need to write your own equals methods, you should always override canEqual if you change equals and hashCode.

With Lombok

01 import lombok.EqualsAndHashCode;
02 
03 @EqualsAndHashCode(exclude={"id""shape"})
04 public class EqualsAndHashCodeExample {
05   private transient int transientVar = 10;
06   private String name;
07   private double score;
08   private Shape shape = new Square(510);
09   private String[] tags;
10   private int id;
11   
12   public String getName() {
13     return this.name;
14   }
15   
16   @EqualsAndHashCode(callSuper=true)
17   public static class Square extends Shape {
18     private final int width, height;
19     
20     public Square(int width, int height) {
21       this.width = width;
22       this.height = height;
23     }
24   }
25 }

Vanilla Java

01 import java.util.Arrays;
02 
03 public class EqualsAndHashCodeExample {
04   private transient int transientVar = 10;
05   private String name;
06   private double score;
07   private Shape shape = new Square(510);
08   private String[] tags;
09   private int id;
10   
11   public String getName() {
12     return this.name;
13   }
14   
15   @Override public boolean equals(Object o) {
16     if (o == thisreturn true;
17     if (!(instanceof EqualsAndHashCodeExample)) return false;
18     EqualsAndHashCodeExample other = (EqualsAndHashCodeExampleo;
19     if (!other.canEqual((Object)this)) return false;
20     if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
21     if (Double.compare(this.score, other.score!= 0return false;
22     if (!Arrays.deepEquals(this.tags, other.tags)) return false;
23     return true;
24   }
25   
26   @Override public int hashCode() {
27     final int PRIME = 59;
28     int result = 1;
29     final long temp1 = Double.doubleToLongBits(this.score);
30     result = (result*PRIME(this.name == null this.name.hashCode());
31     result = (result*PRIME(int)(temp1 ^ (temp1 >>> 32));
32     result = (result*PRIME+ Arrays.deepHashCode(this.tags);
33     return result;
34   }
35   
36   public boolean canEqual(Object other) {
37     return other instanceof EqualsAndHashCodeExample;
38   }
39   
40   public static class Square extends Shape {
41     private final int width, height;
42     
43     public Square(int width, int height) {
44       this.width = width;
45       this.height = height;
46     }
47     
48     @Override public boolean equals(Object o) {
49       if (o == thisreturn true;
50       if (!(instanceof Square)) return false;
51       Square other = (Squareo;
52       if (!other.canEqual((Object)this)) return false;
53       if (!super.equals(o)) return false;
54       if (this.width != other.widthreturn false;
55       if (this.height != other.heightreturn false;
56       return true;
57     }
58     
59     @Override public int hashCode() {
60       final int PRIME = 59;
61       int result = 1;
62       result = (result*PRIMEsuper.hashCode();
63       result = (result*PRIMEthis.width;
64       result = (result*PRIMEthis.height;
65       return result;
66     }
67     
68     public boolean canEqual(Object other) {
69       return other instanceof Square;
70     }
71   }
72 }

Small print

Arrays are 'deep' compared/hashCoded, which means that arrays that contain themselves will result in StackOverflowErrors. However, this behaviour is no different from e.g. ArrayList.

You may safely presume that the hashCode implementation used will not change between versions of lombok, however this guarantee is not set in stone; if there's a significant performance improvement to be gained from using an alternate hash algorithm, that will be substituted in a future version.

For the purposes of equality, 2 NaN (not a number) values for floats and doubles are considered equal, eventhough 'NaN == NaN' would return false. This is analogous to java.lang.Double's equals method, and is in fact required to ensure that comparing an object to an exact copy of itself returns true for equality.

If there is any method named either hashCode, equals or canEqual, regardless of parameters or return type, no methods will be generated, and a warning is emitted instead. These 3 methods need to be in sync with each other, which lombok cannot guarantee unless it generates all the methods, hence you always get a warning if one or more of the methods already exist.

Attempting to exclude fields that don't exist or would have been excluded anyway (because they are static or transient) results in warnings on the named fields. You therefore don't have to worry about typos.

Having both exclude and of generates a warning; the exclude parameter will be ignored in that case.

By default, any variables that start with a $ symbol are excluded automatically. You can only include them by using the 'of' parameter.

If a getter exists for a field to be included, it is called instead of using a direct field reference. This behaviour can be suppressed:
@EqualsAndHashCode(doNotUseGetters = true)