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

Man*_*Joy 27 java java-8 java-stream

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

现在我想合并两个列表并避免基于attrib1和的重复对象attrib2.

使用Java 8:

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

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

Hol*_*ger 24

如果你想实现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());
    }
Run Code Online (Sandbox Code Playgroud)

如果你这样做,distinct()在一个Stream<Parent>遗嘱上调用会自动做正确的事情.


如果您不希望(或不能)更改类Parent,则没有用于相等的委派机制,但您可以使用具有委派机制的排序:

Comparator<Parent> c=Comparator.comparing(Parent::getAttrib1)
        .thenComparing(Parent::getAttrib2)
        .thenComparing(Parent::getAttrib3)
        // …
        .thenComparing(Parent::getAttrib19)
        .thenComparing(Parent::getAttrib20);
Run Code Online (Sandbox Code Playgroud)

这定义了基于属性的订单.它要求属性本身的类型具有可比性.如果您有这样的定义,您可以使用它来实现等效的a distinct(),基于Comparator:

List<Parent> result = Stream.concat(list1.stream(), list2.stream())
        .filter(new TreeSet<>(c)::add)
        .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

如果您想将其与并行流一起使用,还有一个线程安全的变体:

List<Parent> result = Stream.concat(list1.stream(), list2.stream())
        .filter(new ConcurrentSkipListSet<>(c)::add)
        .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • @VivekKothari 不,它是`expression::name` 形式的方法引用的一个基本属性,即首先评估表达式,然后函数接口实例捕获的结果只会调用该对象上的方法。例如,请参阅“[System.out::println 的等效 lambda 表达式是什么?](/sf/answers/1961800221/)”或 [this Q&amp;A](https://stackoverflow.com /q/37979731/2711488) 或 [那个问答](/sf/ask/2136049681/) (2认同)