【问题标题】:Can I change elements while iterating them with Iterable.forEach(Consumer)?我可以在使用 Iterable.forEach(Consumer) 迭代元素时更改元素吗?
【发布时间】:2019-09-15 04:33:00
【问题描述】:

我可以在使用 Iterable.forEach(Consumer) 迭代元素时更改元素吗?或者在 Consumer.accept(E) 中我只能读取底层 Iterable 的元素,但不能更改它们?

如果我可以更改它们,正确的语法是什么?

ArrayDeque d = new ArrayDeque<Integer>();
d.add(1);
d.add(2);
d.add(3);
d.add(4);

Consumer<Integer> cons = (e)->{e = e*10;}; // compiles!

d.forEach(cons);

System.out.println(d); // 1 2 3 4 not 10 20 30 40

【问题讨论】:

    标签: java foreach iterable


    【解决方案1】:

    forEach 采用不返回任何内容的 Consumer 参数,根据您的示例,每个 e 都是 ArrayDeque 中元素的副本,因此您不能使用 forEach 替换元素。

    如果您想为一项任务对每个元素执行e*10(例如打印它们),您可以将ArrayDeque 转换为Stream,然后使用map():

    d.stream().map(e -> e*10).forEach(e -> System.out.println(e));
    

    这样做会显示 Deque 中的每个元素都乘以 10。

    如果你想实际替换ArrayDeque中的元素,

    d = d.stream().map(e -> e*10).collect(Collectors.toCollection(ArrayDeque::new));
    

    【讨论】:

    • AFAI 可以看到 OP 想要改变原始列表,而不仅仅是 sout 修改过的元素,forEach 的语义不允许。
    • @kalimba 好电话。刚刚将解决方法添加到我的回答中:)
    【解决方案2】:

    不,您不能在使用forEach 时修改元素,因为它的actionConsumer,只有accepts 的值。 forEach 方法的示例 sn-p

    default void forEach(Consumer<? super T> action)
     for (T t : this)
         action.accept(t);
    

    主要关注的是它不会产生任何价值。

    【讨论】:

      【解决方案3】:

      您尝试做的与以下内容相同:

      for (Integer e : d) {
         e = e * 10;
      }
      

      但是分配给 e 不会改变它在双端队列中的值。

      做你想做的事,做这个。

       d = d.stream().map(a -> a * 10).collect(
                  Collectors.toCollection(ArrayDeque::new));
       System.out.println(d);
      

      【讨论】:

        【解决方案4】:

        不,你不能。根据documentation for ArrayDeque

        这个类的迭代器方法返回的迭代器是fail-fast:如果在迭代器创建后的任何时候deque被修改,除了通过迭代器自己的remove方法之外,迭代器一般会抛出一个@ 987654322@.

        【讨论】:

          猜你喜欢
          • 2014-06-13
          • 1970-01-01
          • 2022-07-19
          • 2019-03-10
          • 1970-01-01
          • 1970-01-01
          • 2016-09-18
          • 1970-01-01
          相关资源
          最近更新 更多