lombok EqualsAndHashCode on a class which has a list

Viewed 775
@EqualsAndHashcode
MyClass {
String property1;
List<NewClass> newClassList;
}

@EqualsAndHashcode
NewClass {
String abc;
String xyz;
}

If I compare two objects of MyClass (its annotated with @EqualsAndHashcode) for equality, will order of newClassList property be checked ?

2 Answers

By using @EqualsAndHashcode it will propagate to use newClassList.equals(..) method which according to java doc

Interface List

boolean equals(Object o) Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the equals method works properly across different implementations of the List interface.

If you want a custom functionality where list does not check the order then you have to drop @EqualsAndHashcode and provide your own equals method based on what you want.

The functionality that you want would be in a simple way

(list1 != null && list2 != null && list1.size() == list2.size() && list1.containsAll(list2) && list2.containsAll(list1) ) || (list1 == null && list2 == null)

This would lead us to the following equals method

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        NewClass newClass = (NewClass) o;
        return Objects.equals(property1, newClass.property1) &&
                ((newClassList != null && newClass.newClassList != null && newClassList.size() == newClass.newClassList.size() && newClassList.containsAll(newClass.newClassList) && newClass.newClassList.containsAll(newClassList) ) || (newClassList == null && list2 == null));
               
    }

Don't forget also to manually override hashcode method as well.

It depends on what type of comparison do you want to have. Should comparison [1,1,2] == [1,2,2] return true? If yes, then you can convert list to set (and maybe you should use the Set in the class as well):

public boolean equals(Object o) {
  if (this == o) return true;
  if (o == null || getClass() != o.getClass()) return false;
  MyClass that = (MyClass) o;
  if (this.newClassList == null && that. newClassList == null) return true;
  if (this.newClassList != null && that.newClassList != null
      && this.newClassList.size() == that.newClassList.size()) {
    return new HashSet(this.newClassList).equals(new HashSet(that.newClassList));
  }
  return false;
}

otherwise, you have to sort the elements of the list and compare them:

public boolean equals(Object o) {
    // same code as before, except the HashSet part
    List<NewClass> one = new ArrayList<NewClass>(this.newClassList); 
    List<NewClass> two = new ArrayList<NewClass>(that.newClassList);   
    Collections.sort(one);
    Collections.sort(two);      
    return one.equals(two);

Plus, you have to define its own comparator for NewClass, so the sort method knows how to sort the elements.

Related