合并 java 中的两个对象列表 8
Merging two List of objects in java 8
我有一个 Java class Parent
具有 20 个属性 (attrib1, attrib2 .. attrib20)
及其相应的 getter 和 setter。我还有两个 Parent
对象列表:list1
和 list2
.
现在我想合并两个列表并避免基于 attrib1
和 attrib2
的重复对象。
使用 Java 8:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.distinct()
.collect(Collectors.toList());
但是我必须在哪个地方指定属性?我应该覆盖 hashCode
和 equals
方法吗?
覆盖 Parent
class 中的 equals
和 hashCode
方法以避免列表重复。这将为您提供您想要的确切结果。
如果您想覆盖 .equals(…)
和 .hashCode()
,您需要在 Parent
class 上这样做。请注意,这可能会导致 Parent
的其他用途失败。 Alexis C. 的链接解决方案更保守。
例如:
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
,执行的地方是 inside the class Parent
.在那个 class 中添加像
这样的方法
@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<Parent>
上调用的 distinct()
将自动执行正确的操作。
如果您不想(或不能)更改 class 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());
我有一个 Java class Parent
具有 20 个属性 (attrib1, attrib2 .. attrib20)
及其相应的 getter 和 setter。我还有两个 Parent
对象列表:list1
和 list2
.
现在我想合并两个列表并避免基于 attrib1
和 attrib2
的重复对象。
使用 Java 8:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.distinct()
.collect(Collectors.toList());
但是我必须在哪个地方指定属性?我应该覆盖 hashCode
和 equals
方法吗?
覆盖 Parent
class 中的 equals
和 hashCode
方法以避免列表重复。这将为您提供您想要的确切结果。
如果您想覆盖 .equals(…)
和 .hashCode()
,您需要在 Parent
class 上这样做。请注意,这可能会导致 Parent
的其他用途失败。 Alexis C. 的链接解决方案更保守。
例如:
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
,执行的地方是 inside the class Parent
.在那个 class 中添加像
@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<Parent>
上调用的 distinct()
将自动执行正确的操作。
如果您不想(或不能)更改 class 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());