Java - 删除一个集合中另一个集合中的对象,具有任意含义 "equals"

Java - remove objects in a collection that are in another collection, with an arbitrary meaning of "equals"

如果我只想以绝对平等为基础,这很容易。我只想做:

collectionA.removeAll(collectionB).

但是,假设我有这个对象:

class Item {
   private String color;
   private String name;
   private String type;
}

还有两个合集...

List<Item> items1, List<item> items2.

...但我只想从 item1 中删除与 item2 中具有相同 名称和类型 的所有内容。

请注意,我不能子class 或定义等号,为此 class 的哈希码。

我希望这与现有 collections.removeAll 方法的复杂性相同。

我能想到的最佳解决方案如下:

class SimpleItem {
  String name;
  String type;
  Item item;

  public SimpleItem(Item item) {
    this.name = item.getName();
    this.type = item.getType();
  }

  @Override
  public boolean equals(Object obj) {
    ...
  }

  @Override
  public int hashCode() {
    ...
  }
}

Set<SimpleItem> simpleItems1 = ...;
for (Item item : items1) {
  simpleItems1.add(new SimpleItem(item));
}

Set<SimpleItem> simpleItems2 = ...;
for (Item item : items2) {
  simpleItems2.add(new SimpleItem(item));
}

simpleItems1.removeAll(simpleItems2);

Set<Item> items = ...;
for (SimpleItem simpleItem : simpleItems) {
  items.add(simpleItem.item);
}

...但这太冗长了。是 Java 8. 我错过了什么巧妙的解决方案?

您可以使用 apache commons class to do so. Good examples are here

Another link

你提到它是 Java 8。在那种情况下,你有一个非常简单直接的方法来实现它:

list1.removeIf(item1 -> list2.stream().anyMatch(item2 -> customEquals(item1, item2));

如果您的 customEquals 方法是 Item 的成员,您可以使用方法参考使其更整洁:

list1.removeIf(item -> list2.stream().anyMatch(item::customEquals));

在您的情况下,您可以将条件直接放入语句中,而不是创建一个单独的方法:

list1.removeIf(item1 -> list2.stream().anyMatch(item2 ->
    item1.getName().equals(item2.getName()) && item1.getType().equals(item2.getType())));

方便的是 removeIfCollection 接口的默认成员,因此只要实现的迭代器支持 [=18],任何实现 Collection 的 class 都应该支持它=].