Lombok @EqualsAndHashCode example

In this article, we will take a look at lombok @EqualsAndHashCode annotation usage and configuration options with examples.

Lombok @EqualsAndHashCode
@EqualsAndHashCode annotation is applied over a class and it generates java equals() and hashCode() methods automatically.

Without this annotation or a class without lombok support, you need to write these methods yourself as shown below

public class User {

  private String name;

  private int age;

  @Override
  public boolean equals(Object o) {
    // implementation
  }

  @Override
  public int hashCode() {
    // implementation
  }

With lombok, above class can be reduced to

import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class User {

  private String name;

  private int age;
}

This will automatically generate equals() and hashCode() methods internally.

Example,

public class EqualsAndHashCodeTest {
  public static void main(String[] args) {
    User u = new User();
    u.setName("A");
    u.setAge(22);
    System.out.println("Hashcode of first user is: " + u.hashCode());
    // create second user
    User u1 = new User();
    u1.setName("B");
    u1.setAge(35);
    System.out.println("Hashcode of second user is: " + u1.hashCode());
    System.out.println("Equals: " + u.equals(u1));
    // change values
    u1.setAge(22);
    u1.setName("A");
    System.out.println("Equals: " + u.equals(u1));
  }
}

Output is

Hashcode of first user is: 4844
Hashcode of second user is: 5612
Equals: false
Equals: true

Two user objects with different values are created and compared with equals(), the result is false.
When second user is given same values as the first user, equals() returns true.

Ignore properties
Generated hashCode() takes all the fields of the class into account for generating hash code.
Similarly,  equals() method compares all the fields of class to confirm if two objects are equal or not.

If you want to skip some properties, use exclude option of @EqualsAndHashCode as

@EqualsAndHashCode(exclude="age")

Now, equals() will not compare this field while checking for equality of two objects. Also, hashCode() will not consider it for generating hash code.

If there are more than one fields, they should be enclosed in an array.

@EqualsAndHashCode(exclude={"age", "name"})

exclude option will soon deprecated. You must use @EqualsAndHashCode.Exclude over the fields that need to be skipped. Example,

import lombok.EqualsAndHashCode; 

@EqualsAndHashCode 
public class User { 

  private String name; 

  @EqualsAndHashCode.Exclude 
  private int age; 
}

Example,

public class EqualsAndHashCodeTest { 
  public static void main(String[] args) { 
    User u = new User(); 
    u.setName("A"); 
    u.setAge(22); 
    User u1 = new User(); 
    u1.setName("A"); 
    u1.setAge(35); 
    System.out.println("Equals: " + u.equals(u1)); // true
  } 
}

Even though the age of both user objects is different, equals() returns true. This is because, age field is excluded from comparison in equals().

Alternatively, you can mark fields that need to be included in equals() and hashCode() implementation with @EqualsAndHashCode.Include as shown below

import lombok.EqualsAndHashCode; 

@EqualsAndHashCode(onlyExplicitlyIncluded = true) 
public class User { 

  @EqualsAndHashCode.Include 
  private String name; 

  private int age; 
}

Note that with Include option, you need to also set onlyExplicitlyIncluded option to true with @EqualsAndHashCode to indicate that it should only include fields, that are explicitly stated.
@EqualsAndHashCode with parent class
If a class annotated with @EqualsAndHashCode, extends another class, then its equals() and hashCode() methods do not consider parent class fields.
This makes the implementation of equals() and hashCode() faulty.

Lombok provides a solution in the form of callSuper option. When set to true, equals() and hashCode() methods also include parent class fields in generated implementation. Example,

import lombok.EqualsAndHashCode;

public class Person {

  private Integer id;
}

@EqualsAndHashCode(callSuper = true)
public class User extends Person {

  private String name;

  private int age;
}

Default value of callSuper is false.

If your class extends another class and you do not supply callSuper value(either true or false), then a warning is generated

Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add ‘@EqualsAndHashCode(callSuper=false)’ to your type.

If your class does not extend any class but callSuper is set to true raises a compile time error

Generating equals/hashCode with a supercall to java.lang.Object is pointless.

This is because this would mean that you are inheriting these methods(which is already being done anyway) and not generating any specific code.

Hope the article was useful.