合并Java 8中的两个对象列表

时间:2015-06-16 11:51:31

标签: java java-8 java-stream

我有一个Java类Parent,其中包含20个属性(attrib1, attrib2 .. attrib20)及其相应的getter和setter。此外,我还有两个Parent个对象列表:list1list2

现在我想合并两个列表,避免基于attrib1attrib2的重复对象。

使用Java 8:

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

但是我必须在哪个地方指定属性?我应该覆盖hashCodeequals方法吗?

4 个答案:

答案 0 :(得分:22)

如果您要实施equalshashCode,则可以在内部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());

答案 1 :(得分:1)

例如:

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

答案 2 :(得分:0)

覆盖equals类中的hashCodeParent方法,以避免重复列表。这将为您提供您想要的确切结果。

答案 3 :(得分:0)

如果您要覆盖.equals(…).hashCode(),则需要在Parent课程上执行此操作。请注意,这可能会导致Parent的其他用途失败。 Alexis C.的链接解决方案更加保守。