Reputation: 1769
I have a Java class Parent
with 20 attributes (attrib1, attrib2 .. attrib20)
and its corresponding getters and setters. Also I have two lists of Parent
objects: list1
and list2
.
Now I want to merge both lists and avoid duplicate objects based on attrib1
and attrib2
.
Using Java 8:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.distinct()
.collect(Collectors.toList());
But in which place I have to specify the attributes? Should I override hashCode
and equals
method?
Upvotes: 34
Views: 63045
Reputation: 981
Override the equals
and hashCode
methods in Parent
class to avoid duplicates from the lists. This will give you the exact result what you want.
Upvotes: 1
Reputation: 298123
If you want to implement equals
and hashCode
, the place to do it is inside the class Parent
. Within that class add the methods like
@Override
public int hashCode() {
return Objects.hash(getAttrib1(), getAttrib2(), getAttrib3(),
// …
getAttrib19(), getAttrib20());
}
@Override
public boolean equals(Object obj) {
if(this==obj) return true;
if(!(obj instanceof Parent)) return false;
Parent p=(Parent) obj;
return Objects.equals(getAttrib1(), p.getAttrib1())
&& Objects.equals(getAttrib2(), p.getAttrib2())
&& Objects.equals(getAttrib3(), p.getAttrib3())
// …
&& Objects.equals(getAttrib19(), p.getAttrib19())
&& Objects.equals(getAttrib20(), p.getAttrib20());
}
If you did this, distinct()
invoked on a Stream<Parent>
will automatically do the right thing.
If you don’t want (or can’t) change the class Parent
, there is no delegation mechanism for equality, but you may resort to ordering as that has a delegation mechanism:
Comparator<Parent> c=Comparator.comparing(Parent::getAttrib1)
.thenComparing(Parent::getAttrib2)
.thenComparing(Parent::getAttrib3)
// …
.thenComparing(Parent::getAttrib19)
.thenComparing(Parent::getAttrib20);
This defines an order based on the properties. It requires that the types of the attributes itself are comparable. If you have such a definition, you can use it to implement the equivalent of a distinct()
, based on that Comparator
:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.filter(new TreeSet<>(c)::add)
.collect(Collectors.toList());
There is also a thread-safe variant, in case you want to use it with parallel streams:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.filter(new ConcurrentSkipListSet<>(c)::add)
.collect(Collectors.toList());
Upvotes: 32
Reputation:
For example:
public class Parent {
public int no;
public String name;
@Override
public int hashCode() {
return (no << 4) ^ name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Parent))
return false;
Parent o = (Parent)obj;
return this.no == o.no && this.name.equals(o.name);
}
}
Upvotes: 1
Reputation: 14511
If you want to override .equals(…)
and .hashCode()
, you need to do so on the Parent
class. Note that this may cause other uses of Parent
to fail. Alexis C.'s linked solution is more conservative.
Upvotes: 0