'How to filter objects contained in two Sets based on a single property without overriding equals() and hashCode()
I have a set of objects and trying to find if an object exist in list by id. I do not want to override equals() and hashCode().
class ABC {
Long id;
String name;
}
I want to do the below statement without overriding equals() and hashCode() methods
Set<ABC> abcSetOne;
Set<ABC> abcSetTwo;
abcSetOne.stream()
.filter(abcSetTwo::contains)
.collect(Collectors.toSet());
ids are guaranteed unique.
I am using Java 8.
Solution 1:[1]
Objects equality based on a single attribute
When need set intersection (in terms of set theory) of your object based on one attribute only without changing the existing hashCode() and equals() methods, you can create a HashSet of ids.
public static void main(String[] args) {
Set<ABC> abcSetOne = Set.of(new ABC(1L, "first"), new ABC(2L, "second"), new ABC(3L, "third"));
Set<ABC> abcSetTwo = Set.of(new ABC(1L, "first"), new ABC(5L, "fifth"), new ABC(3L, "third"));
Set<Long> idsOne = abcSetTwo.stream()
.map(ABC::getId)
.collect(Collectors.toSet());
Set<ABC> result = abcSetOne.stream()
.filter(abc -> idsOne.contains(abc.getId()))
.collect(Collectors.toSet());
System.out.println(result);
}
Output
[ABC{id=1, name='first'}, ABC{id=3, name='third'}]
Objects equality based on multiple attributes
When you need to establish uniqueness based on more than one object's property, you can define a wrapper class with the hashCode/equals contract implemented based on these properties.
As a wrapper you can utilize of Java 16 record, that will make the code leaner (hashCode() and equals() will be generated by the compiler)
public record ABCWrapper(Long id, String name) {
ABCWrapper(Wrapping.ABC abc) {
this(abc.getId(), abc.getName());
}
}
For earlier versions, ABCWrapper can be defined as a plain class.
main() - demo
public static void main(String[] args) {
Set<ABC> abcSetOne = Set.of(new ABC(1L, "first"), new ABC(2L, "second"), new ABC(3L, "third"));
Set<ABC> abcSetTwo = Set.of(new ABC(1L, "first"), new ABC(5L, "fifth"), new ABC(3L, "third"));
Map<ABCWrapper, ABC> abcByWrapper = abcSetTwo.stream()
.collect(Collectors.toMap(ABCWrapper::new, Function.identity()));
Set<ABC> result = abcSetOne.stream()
.map(ABCWrapper::new)
.filter(abcByWrapper::containsKey)
.map(abcByWrapper::get)
.collect(Collectors.toSet());
System.out.println(result);
}
Output
[ABC{id=1, name='first'}, ABC{id=3, name='third'}]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
