合并Java 8中的两个对象列表
我有一个Java类Parent
有20个属性(attrib1, attrib2 .. attrib20)
及其相应的getter和setter。 我还有两个Parent
对象列表: list1
和list2
。
现在我想合并两个列表并避免基于attrib1
和attrib2
重复对象。
使用Java 8:
List result = Stream.concat(list1.stream(), list2.stream()) .distinct() .collect(Collectors.toList());
但是我必须在哪个地方指定属性? 我应该覆盖hashCode
和equals
方法吗?
如果你想实现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()); }
如果你这样做,在Stream
上调用distinct()
将自动做正确的事情。
如果您不希望(或不能)更改类Parent
,则没有用于相等的委派机制,但您可以使用具有委派机制的排序 :
Comparator c=Comparator.comparing(Parent::getAttrib1) .thenComparing(Parent::getAttrib2) .thenComparing(Parent::getAttrib3) // … .thenComparing(Parent::getAttrib19) .thenComparing(Parent::getAttrib20);
这定义了基于属性的订单。 它要求属性本身的类型具有可比性。 如果你有这样的定义,你可以使用它来实现基于该Comparator
的distinct()
的等价物:
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
类中的equals
和hashCode
方法,以避免列表中的重复。 这将为您提供您想要的确切结果。