In this guide we will explore how to use Lombok @EqualsAndHashCode annotation with several examples.
- 1. Lombok @EqualsAndHashCode
- 2. Lombok @EqualsAndHashCode vs static and transient fields
- 3. Excluding fields from equals and hashCode methods
- 4. Include only specific fields/methods to equals and hashCode methods
- 5. Lombok @EqualsAndHashCode callSuper
- 6. doNotUseGetters
- 7. Put annotations on Generated equals and canEqual methods
- 8. Conclusion
1. Lombok @EqualsAndHashCode
When we declare a class with @EqualsAndHashCode, Lombok generates implementations for the equals
and hashCode
methods. Following example demonstrates how lombok generated equals
and hashcode
methods looks like.
Make sure you already installed Lombok setup for your IDE. To Setup in Eclipse or in Spring Tool Suite refer to our Lombok Maven example setup with Eclipse.
Lomboked EqualsHashCodeDemo1.java
@EqualsAndHashCode public class EqualsHashCodeDemo1 { private Long id; private String username; }
DeLomboked EqualsHashCodeDemo1.java
public class EqualsHashCodeDemo1 { private Long id; private String name; @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo1)) return false; final EqualsHashCodeDemo1 other = (EqualsHashCodeDemo1) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; final Object this$name = this.name; final Object other$name = other.name; if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof EqualsHashCodeDemo1; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); final Object $name = this.name; result = result * PRIME + ($name == null ? 43 : $name.hashCode()); return result; } }
2. Lombok @EqualsAndHashCode vs static and transient fields
By default Lombok @EqualsAndHashCode
uses non-static and non-transient fields to generate equals
and hashCode
methods.
Lomboked EqualsHashCodeDemo2.java
@EqualsAndHashCode public class EqualsHashCodeDemo2 { private Long id; private static int defaultRole = 1; private LocalDate dob; private transient String dobString; }
DeLomboked EqualsHashCodeDemo2.java
public class EqualsHashCodeDemo2 { private Long id; private static int defaultRole = 1; private LocalDate dob; private transient String dobString; @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo2)) return false; final EqualsHashCodeDemo2 other = (EqualsHashCodeDemo2) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; final Object this$dob = this.dob; final Object other$dob = other.dob; if (this$dob == null ? other$dob != null : !this$dob.equals(other$dob)) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof EqualsHashCodeDemo2; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); final Object $dob = this.dob; result = result * PRIME + ($dob == null ? 43 : $dob.hashCode()); return result; } }
3. Excluding fields from equals and hashCode methods
Lombok provides class level exclusion and field level exclusion to not include fields from generating equals
and hashCode
methods.
3.1. Field level exclusion
Fields are marked with @EqualsAndHashCode.Exclude are excludes from generated equals
and hashCode
methods.
Lomboked EqualsHashCodeDemo3.java
@EqualsAndHashCode public class EqualsHashCodeDemo3 { private Long id; @EqualsAndHashCode.Exclude private String name; @EqualsAndHashCode.Exclude private String email; }
DeLomboked EqualsHashCodeDemo3.java
public class EqualsHashCodeDemo3 { private Long id; private String name; private String email; @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo3)) return false; final EqualsHashCodeDemo3 other = (EqualsHashCodeDemo3) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof EqualsHashCodeDemo3; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); return result; } }
3.2. Class level exclusion
To exclude fields from generating hashCode
and equals
methods by Lombok you can use exclude
attribute like @EqualsAndHashCode(exclude = {"field1", "field2", ...etc})
Lomboked EqualsHashCodeDemo4.java
@EqualsAndHashCode(exclude = {"name", "email"}) public class EqualsHashCodeDemo4 { private Long id; private String name; private String email; }
DeLomboked EqualsHashCodeDemo4.java
public class EqualsHashCodeDemo4 { private Long id; private String name; private String email; @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo4)) return false; final EqualsHashCodeDemo4 other = (EqualsHashCodeDemo4) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof EqualsHashCodeDemo4; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); return result; } }
4. Include only specific fields/methods to equals and hashCode methods
Lombok provides several ways to include only specific fields/methods to generate hashCode
and equals
methods.
4.1. Include fields/methods
Lombok @EqualsAndHashCode
by default uses non-static and non-transient fields to generate equals
and hashCode
methods. Additionally to include specific method we have to declare @EqualsAndHashCode.Include
on top of method.
Lomboked EqualsHashCodeDemo5.java
@EqualsAndHashCode public class EqualsHashCodeDemo5 { private Long id; @EqualsAndHashCode.Exclude private double salary; @EqualsAndHashCode.Include private boolean isHighPay() { return this.salary > 100000.00; } }
DeLomboked EqualsHashCodeDemo5.java
public class EqualsHashCodeDemo5 { private Long id; private double salary; private boolean isHighPay() { return this.salary > 100000.0; } @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo5)) return false; final EqualsHashCodeDemo5 other = (EqualsHashCodeDemo5) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; if (this.isHighPay() != other.isHighPay()) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof EqualsHashCodeDemo5; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); result = result * PRIME + (this.isHighPay() ? 79 : 97); return result; } }
4.2. Include only specific fields
There are two ways we can include only specific fields like following 2 examples.
4.2.1. Example using onlyExplicitlyIncluded
attribute :
Lomboked EqualsHashCodeDemo6.java
@EqualsAndHashCode(onlyExplicitlyIncluded = true) public class EqualsHashCodeDemo6 { @EqualsAndHashCode.Include private Long id; private double salary; private String email; }
DeLomboked EqualsHashCodeDemo6.java
public class EqualsHashCodeDemo6 { private Long id; private double salary; private String email; @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo6)) return false; final EqualsHashCodeDemo6 other = (EqualsHashCodeDemo6) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof EqualsHashCodeDemo6; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); return result; } }
4.2.2. Example using of
attribute :
Lomboked EqualsHashCodeDemo7.java
@EqualsAndHashCode(of = {"id", "email"}) public class EqualsHashCodeDemo7 { private Long id; private double salary; private String email; }
DeLomboked EqualsHashCodeDemo7.java
public class EqualsHashCodeDemo7 { private Long id; private double salary; private String email; @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo7)) return false; final EqualsHashCodeDemo7 other = (EqualsHashCodeDemo7) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; final Object this$email = this.email; final Object other$email = other.email; if (this$email == null ? other$email != null : !this$email.equals(other$email)) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof EqualsHashCodeDemo7; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); final Object $email = this.email; result = result * PRIME + ($email == null ? 43 : $email.hashCode()); return result; } }
Note : As per Lombok documentation using of
and exclude
attributes with @EqualsAndHashCode
will soon be marked as deprecated, they are old style of inclusion/exclusion of fields in generating equals
and hashCode
methods using Lombok.
5. Lombok @EqualsAndHashCode callSuper
By setting callSuper
to true
, you can include the equals
and hashCode
methods of your superclass in the generated methods. In this case superclass has to override equals
and hashCode
methods. User may have different equals
method implementation, lombok-generated equals
implementations in superclass aswell do handle this situation properly.
Lomboked Rectangle.java and Box.java
@EqualsAndHashCode public class Rectangle { private double width; private double length; }
@AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class Box extends Rectangle { private double height; }
DeLomboked Box.java
public class Box extends Rectangle { private double height; public Box(final double height) { this.height = height; } @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof Box)) return false; final Box other = (Box) o; if (!other.canEqual((Object) this)) return false; if (!super.equals(o)) return false; if (Double.compare(this.height, other.height) != 0) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof Box; } @Override public int hashCode() { final int PRIME = 59; int result = super.hashCode(); final long $height = Double.doubleToLongBits(this.height); result = result * PRIME + (int) ($height >>> 32 ^ $height); return result; } }
Testing Box.java :
public class EqualsHashCodeTest { public static void main(String[] args) { Box b1 = new Box(10.0); Box b2 = new Box(10.0); Box b3 = new Box(11.0); String b4 = "10.0"; String b5 = null; Rectangle r1 = new Box(10.0); Rectangle r2 = r1; Rectangle r3 = new Rectangle(); System.out.println("b1 == b2 => "+(b1 == b2)); System.out.println("b1 == b3 => "+(b1 == b3)); System.out.println("b1 == r1 => "+(b1 == r1)); System.out.println("r1 == r2 => "+(r1 == r2)); System.out.println("b1.equals(b2) => "+b1.equals(b2)); System.out.println("b1.equals(b3) => "+b1.equals(b3)); System.out.println("b1.equals(b4) => "+b1.equals(b4)); System.out.println("b1.equals(b5) => "+b1.equals(b5)); System.out.println("b1.equals(r1) => "+b1.equals(r1)); System.out.println("b1.equals(r2) => "+b1.equals(r2)); System.out.println("b1.equals(r1) => "+b1.equals(r3)); } }
Output results :
b1 == b2 => false b1 == b3 => false b1 == r1 => false r1 == r2 => true b1.equals(b2) => true b1.equals(b3) => false b1.equals(b4) => false b1.equals(b5) => false b1.equals(r1) => true b1.equals(r2) => true b1.equals(r1) => false
6. doNotUseGetters
Normally, if getters are available, they are called instead of using a direct field reference. This behaviour can be changed using @EqualsAndHashCode(doNotUseGetters = true)
. You can also change this by using Lombok configuration using configuration property lombok.equalsAndHashCode.doNotUseGetters
= [true
| false
] (default: false)
Lomboked EqualsHashCodeDemo8.java
@EqualsAndHashCode(doNotUseGetters = true) @Getter public class EqualsHashCodeDemo8 { private Long id; }
DeLomboked EqualsHashCodeDemo8.java
public class EqualsHashCodeDemo8 { private Long id; @Override public boolean equals(final Object o) { if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo8)) return false; final EqualsHashCodeDemo8 other = (EqualsHashCodeDemo8) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; return true; } protected boolean canEqual(final Object other) { return other instanceof EqualsHashCodeDemo8; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); return result; } public Long getId() { return this.id; } }
7. Put annotations on Generated equals and canEqual methods
Sometimes you may want to declare annotations to the parameter of equals
method, for example if you wants to make parameter non-null. onParam
attribute of @EqualsAndHashCode
allows us to put annotations on generated parameter of equals and canEqual
methods.
- Up to JDK7:
@EqualsAndHashCode([email protected]__({@AnnotationsGoHere}))
- From JDK8:
@EqualsAndHashCode(onParam_={@AnnotationsGohere})
// note the underscore afteronParam
.
Lomboked EqualsHashCodeDemo9.java
@EqualsAndHashCode(onParam_= @NonNull) public class EqualsHashCodeDemo9 { private Long id; }
DeLomboked EqualsHashCodeDemo9.java
public class EqualsHashCodeDemo9 { private Long id; @Override public boolean equals(@NonNull final Object o) { if (o == null) { throw new NullPointerException("o is marked non-null but is null"); } if (o == this) return true; if (!(o instanceof EqualsHashCodeDemo9)) return false; final EqualsHashCodeDemo9 other = (EqualsHashCodeDemo9) o; if (!other.canEqual((Object) this)) return false; final Object this$id = this.id; final Object other$id = other.id; if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; return true; } protected boolean canEqual(@NonNull final Object other) { return other instanceof EqualsHashCodeDemo9; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $id = this.id; result = result * PRIME + ($id == null ? 43 : $id.hashCode()); return result; } }
8. Conclusion
In this guide we have covered Lombok EqualsAndHashCode annotation examples with different options. You can refer Delombok Maven example to see how looks like lombok generated code for your Lomboked classes.
You can checkout source code at github.
You might be interested in our other following Lombok Tutorials :
- Lombok @Getter @Setter and lazy getters
- Lombok @ToString
- Lombok @AllArgsConstructor
- Lombok @NoArgsConstructor
- Lombok @RequiredArgsConstructor
- Lombok @Accessors
- Lombok @Data
- Lombok Spring Boot Maven example