HomeLombokLombok @EqualsAndHashCode examples

Lombok @EqualsAndHashCode examples

In this guide we will explore how to use Lombok @EqualsAndHashCode annotation with several examples.

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.

  1. Up to JDK7: @EqualsAndHashCode([email protected]__({@AnnotationsGoHere}))
  2. From JDK8: @EqualsAndHashCode(onParam_={@AnnotationsGohere}) // note the underscore after onParam.

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 :

  1. Lombok @Getter @Setter and lazy getters
  2. Lombok @ToString
  3. Lombok @AllArgsConstructor
  4. Lombok @NoArgsConstructor
  5. Lombok @RequiredArgsConstructor
  6. Lombok @Accessors
  7. Lombok @Data
  8. Lombok Spring Boot Maven example

LEAVE A REPLY

Please enter your comment!
Please enter your name here