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

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

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

使用Java 8:

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

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

如果你想实现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()); } 

如果你这样做,在Stream上调用distinct()将自动做正确的事情。


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

 Comparator c=Comparator.comparing(Parent::getAttrib1) .thenComparing(Parent::getAttrib2) .thenComparing(Parent::getAttrib3) // … .thenComparing(Parent::getAttrib19) .thenComparing(Parent::getAttrib20); 

这定义了基于属性的订单。 它要求属性本身的类型具有可比性。 如果你有这样的定义,你可以使用它来实现基于该Comparatordistinct()的等价物:

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

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

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

例如:

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

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

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