Подтвердить что ты не робот

Объединение двух списков объектов в java 8

У меня есть класс Java Parent с 20 атрибутами (attrib1, attrib2 .. attrib20) и его соответствующими геттерами и сеттерами. Также у меня есть два списка объектов Parent: list1 и list2.

Теперь я хочу объединить оба списка и избежать дублирования объектов на основе attrib1 и attrib2.

Использование Java 8:

List<Parent> result = Stream.concat(list1.stream(), list2.stream())
                .distinct()
                .collect(Collectors.toList());   

Но где я должен указать атрибуты? Должен ли я переопределить метод hashCode и equals?

4b9b3361

Ответ 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());

Ответ 2

Переопределите методы equals и hashCode в классе Parent, чтобы избежать дублирования списков. Это даст вам точный результат, который вы хотите.

Ответ 3

Если вы хотите переопределить .equals(…) и .hashCode(), вам нужно сделать это в классе Parent. Обратите внимание, что это может привести к сбою других использования Parent. Связанное с Alexis C. решение более консервативно.

Ответ 4

Например:

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);
    }
}