Comparing two class instances with many attributes

I have a class that has over 30 attributes.

I want to override the equals method to compare two instances of my class.

However, I want to avoid re-writing all 30 attributes in my method, since this is

@Override
public boolean equals(java.lang.Object o) {
    if (this == o) {
        return true;
    }
    if (o == null || getClass() != o.getClass()) {
        return false;
    }
    Address address = (Address) o;
    return Objects.equals(this.attr1, address.attr1) &&
            Objects.equals(this.attr2, address.attr2) &&
            Objects.equals(this.attr3, address.attr3) &&
            ......
            Objects.equals(this.attr30, address.attr30);

}

Do you have an easier and more correct way?

+4
source share
5 answers

Well, this is basically the type of template code that is needed. Fortunately, there are many developers who are just as annoying to write code like you. For such reasons, Project Lombok was created.

Please see this link.

As an example, see the following two code snippets extracted from the page I linked to above:

Lombok

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(exclude={"id", "shape"})
public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;

  public String getName() {
    return this.name;
  }

  @EqualsAndHashCode(callSuper=true)
  public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

Vanilla java

import java.util.Arrays;

public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;

  public String getName() {
    return this.name;
  }

  @Override public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof EqualsAndHashCodeExample)) return false;
    EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
    if (!other.canEqual((Object)this)) return false;
    if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
    if (Double.compare(this.score, other.score) != 0) return false;
    if (!Arrays.deepEquals(this.tags, other.tags)) return false;
    return true;
  }

  @Override public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final long temp1 = Double.doubleToLongBits(this.score);
    result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
    result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
    result = (result*PRIME) + Arrays.deepHashCode(this.tags);
    return result;
  }

  protected boolean canEqual(Object other) {
    return other instanceof EqualsAndHashCodeExample;
  }

  public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }

    @Override public boolean equals(Object o) {
      if (o == this) return true;
      if (!(o instanceof Square)) return false;
      Square other = (Square) o;
      if (!other.canEqual((Object)this)) return false;
      if (!super.equals(o)) return false;
      if (this.width != other.width) return false;
      if (this.height != other.height) return false;
      return true;
    }

    @Override public int hashCode() {
      final int PRIME = 59;
      int result = 1;
      result = (result*PRIME) + super.hashCode();
      result = (result*PRIME) + this.width;
      result = (result*PRIME) + this.height;
      return result;
    }

    protected boolean canEqual(Object other) {
      return other instanceof Square;
    }
  }
}

, Lombok. !

!!! ! , Lombok, Lombok IDE! IDE .

+2

Field java.lang.reflect, :

@Override
public boolean equals(Object o) {
    //instanceof check, null check, etc

    Field[] fields = Address.class.getDeclaredFields();

    for (Field field : fields) {
        try {
            field.setAccessible(true);

            if (!field.get(this).equals(field.get((Address) o))) {
                return false;
            } //end if
        } catch (IllegalAccessException e) {
            //handle exception
        } //end try catch
    } //end for

    return true;
} //equals
+3

apache commons, .

org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(Object, Object)

import org.apache.commons.lang.builder.EqualsBuilder;

public class MyObject {

   ...
   @Override
   public boolean equals(Object obj) {
      return EqualsBuilder.reflectionEquals(this, obj);
  }
}
+2

lombok hashCode .

+2

Unitils http://www.unitils.org/cookbook.html

import static org.unitils.reflectionassert.ReflectionAssert.*;
// Exact field-by-field comparison
assertReflectionEquals(new Person("John", "Doe", new Address("New street", 5, "Brussels")), 
                             new Person("John", "Doe", new Address("New street", 5, "Brussels"));
+1

Source: https://habr.com/ru/post/1696164/


All Articles