Ответ 1
Если вы хотите реализовать equals
и hashCode
, то место, которое нужно сделать, находится внутри класса Parent
. Внутри этого класса добавьте такие методы, как
@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());
}
Если вы это сделали, distinct()
, вызванный на Stream<Parent>
, автоматически сделает все правильно.
Если вы не хотите (или не можете) изменить класс Parent
, для равенства не существует механизма делегирования, но вы можете прибегнуть к упорядочению, поскольку у него есть механизм делегирования:
Comparator<Parent> c=Comparator.comparing(Parent::getAttrib1)
.thenComparing(Parent::getAttrib2)
.thenComparing(Parent::getAttrib3)
// …
.thenComparing(Parent::getAttrib19)
.thenComparing(Parent::getAttrib20);
Это определяет порядок, основанный на свойствах. Это требует, чтобы типы самих атрибутов были сопоставимы. Если у вас есть такое определение, вы можете использовать его для реализации эквивалента distinct()
на основе этого Comparator
:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.filter(new TreeSet<>(c)::add)
.collect(Collectors.toList());
Существует также вариант с потоковой безопасностью, если вы хотите использовать его с параллельными потоками:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.filter(new ConcurrentSkipListSet<>(c)::add)
.collect(Collectors.toList());