如何在 foreach 方法中从流中删除对象?

新手上路,请多包涵

我必须数组: arrAarrBarrA and arrB are Lists of objectss of diffrent types and add function converts objects A to objects B .我想将每个对象从 arrA 添加到 arrB 并从 arrA 中删除该对象。我试图通过流来做到这一点:

 arrA.stream().foreach(c -> {arrB.add(c); arrA.remove(c);});

当我执行此操作时,发生了两件事:

  1. 并非所有对象都从 arrA 传递到 arrB。
  2. 几次迭代后抛出空指针异常。

我猜这是因为数组的长度在每次 remove() 调用后减少并且迭代计数器增加(只有奇数索引下的对象被传递给 arrB

现在我可以通过在一个流调用中复制数组然后在第二个流调用中删除对象来解决这个问题,但这对我来说似乎不正确。

什么是解决这个问题的正确方法?

编辑。附加信息:在实际实现中,如果以前过滤过,则此列表

arrA.stream().filter(some condition).foreach(c -> {arrB.add(c); arrA.remove(c);});

并且它被调用了几次以将满足不同条件的元素添加到不同的列表( arrC, arrD 等)但每个对象只能在一个列表中

原文由 Akka Jaworek 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 416
2 个回答

流旨在以更实用的方式使用,最好将您的集合视为不可变的。

非流方式是:

 arrB.addAll(arrA);
arrA.clear();

但是,您可能正在使用 Streams,因此您可以过滤输入,使其更像是:

 arrB.addAll(arrA.stream().filter(x -> whatever).toList())

然后从 arrA 中删除(感谢@Holgar 的评论)。

 arrA.removeIf(x -> whatever)

如果您的谓词很昂贵,那么您可以分区:

 Map<Boolean, XXX> lists = arrA.stream()
  .collect(Collectors.partitioningBy(x -> whatever));
arrA = lists.get(false);
arrB = lists.get(true);

或列出更改:

 List<XXX> toMove = arrA.stream().filter(x->whatever).toList();
arrA.removeAll(toMove);
arrB.addAll(toMove);

原文由 davidsheldon 发布,翻译遵循 CC BY-SA 3.0 许可协议

正如其他人所提到的, foreach 这是不可能的 - 因为 for (A a: arrA) 循环是不可能删除元素的。

在我看来,最干净的解决方案是使用带有迭代器的普通 for while 迭代器允许您在迭代时删除元素(只要集合支持)。

 Iterator<A> it = arrA.iterator()
while (it.hasNext()) {
    A a = it.next();
    if (!check(a))
        continue;
    arrB.add(a);
    it.remove();
}

这也使您免于复制/克隆 arrA

原文由 Martin Nyolt 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题