【问题标题】:How to print a count in Collections.forEach() [duplicate]如何在 Collections.forEach() 中打印计数 [重复]
【发布时间】:2016-04-18 14:14:29
【问题描述】:

所以我有一个列表如下,带有 lambda 表达式:

ArrayList<String> array = new ArrayList<>();
...
StringBuffer buf = new StringBuffer("");
array.stream().forEach((item) -> {
    buf.append("Counter here: " + item.toString() + "\n");
});
return buf.toString();

但是我不能在forEach lambda 表达式中实例化和修改变量,因为它必须是final。有什么办法可以做到吗?

【问题讨论】:

  • 我不明白。你想要每个元素的索引吗?
  • 是的,或者只是一个计数器,例如 '0: ...' 和 '1: ...'
  • MutableInteger 在 apache-lang 中可用,其开销比 AtomicInteger 少。还要避免使用 StringBuffer 作为局部变量使用 StringBuilder (StringBuffer 是同步的,而 StringBuilder 不是,除非您要使用多个线程更新该缓冲区,否则会产生额外的成本而没有好处)。

标签: java java-8


【解决方案1】:

为此使用原子:

AtomicInteger cnt = new AtomicInteger(0);
StringBuilder buf = new StringBuilder("");
array.stream().forEach((item) -> {
    buf.append("Counter here: " + cnt.incrementAndGet() + "\n");
});
return buf.toString();

【讨论】:

  • 此代码会不会抛出错误以使buf final实际上是最终的 ??
  • @LalitRao cntbuf 实际上是最终的,这里没有错误。它可以在 Java 8 上正常工作。
  • 你能详细解释一下吗?我的意思是我们正在改变 lambda 中 buf 的状态,对吗?那么它如何有效地保持最终状态呢?
  • @LalitRao 简而言之:您可以修改从 lambda 表达式引用的对象的内部状态。但是您不能自己更改对象引用,例如buf.toString()cnt.incrementAndGet() 是允许的,但 buf = buf.append("test") 或例如 i = i + 1i++ 是不允许的
  • 谢谢队友 :) 解释得很好
【解决方案2】:

使用大小为 1 的 int[] 作为计数器:

ArrayList<String> array = new ArrayList<>();
int[] count = {0};
return array.stream().map(item -> count[0]++ + ":" + item)
  .collect(Collectors.joining("\n", "", "\n"));

int[] 实际上是最终的。它的内容不一定是。

请注意,如果您使用 joining() 收集器,您甚至不需要 StringBuilder

【讨论】:

  • &lt;thinks-to-self&gt;我希望有一个功能可以让人们在投票时标记答案中“没用”的地方&lt;/thinks-to-self&gt;
  • &lt;thinks-out-loud&gt;我希望版主和Java金徽章持有者可以投票适当地关闭重复。&lt;/thinks-out-loud&gt;
  • @Pillar 嗯,这个答案不是骗人的,但是好的....
  • 政策不是在那里添加答案而不是关闭欺骗问题吗?无论如何,您应该考虑到没有这样的答案可能有充分的理由......
猜你喜欢
  • 2023-04-10
  • 2021-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 2018-11-19
相关资源
最近更新 更多