如何在 Java Stream 中增加一个值?
我想通过 1
的每次迭代来增加 index
的值.在for-loop
中很容易实现.变量 image
是 ImageView
的数组.
I want to increment value of index
with the each iteration by 1
. Easily to be achieved in the for-loop
. The variable image
is an array of ImageView
.
这是我的 for-loop
.
for (Map.Entry<String, Item> entry : map.entrySet()) {
image[index].setImage(entry.getValue().getImage());
index++;
}
为了练习Stream,我尝试将其重写为Stream
:
In order to practise Stream, I have tried to rewrite it to the Stream
:
map.entrySet().stream()
.forEach(e -> item[index++].setImage(e.getValue().getImage()));
导致我的错误:
错误:从 lambda 表达式引用的局部变量必须是 final 或有效 final
error: local variables referenced from a lambda expression must be final or effectively final
如何重写Stream
递增变量index
要使用?
How to rewrite the Stream
incrementing the variable index
to be used in?
推荐答案
你不应该.这两个看起来很相似,但它们在概念上是不同的.循环只是一个循环,但 forEach
指示库对每个元素执行操作,既没有指定操作的顺序(对于并行流)也没有指定将执行它们的线程.如果你使用forEachOrdered
,那么仍然不能保证线程,但至少你可以保证后续元素上的动作之间的happens-before关系.
You shouldn't. These two look similar, but they are conceptually different. The loop is just a loop, but a forEach
instructs the library to perform the action on each element, without specifying neither the order of actions (for parallel streams) nor threads which will execute them. If you use forEachOrdered
, then there are still no guarantees about threads, but at least you have the guarantee of happens-before relationship between actions on subsequent elements.
请特别注意 文档 说:
对于任何给定的元素,动作可以在任何时间执行以及图书馆选择的任何线程.如果操作访问共享状态,它负责提供所需的同步.
For any given element, the action may be performed at whatever time and in whatever thread the library chooses. If the action accesses shared state, it is responsible for providing the required synchronization.
正如@Marko 在下面的评论中指出的那样,它只适用于并行流,即使措辞有点混乱.不过,使用循环意味着您甚至不必担心所有这些复杂的事情!
As @Marko noted in the comments below, though, it only applies to parallel streams, even if the wording is a bit confusing. Nevertheless, using a loop means that you don't even have to worry about all this complicated stuff!
所以底线是:如果该逻辑是它所在函数的一部分,则使用循环,如果您只想告诉 Java 对流.
So the bottom line is: use loops if that logic is a part of the function it's in, and use forEach
if you just want to tell Java to "do this and that" to elements of the stream.
那是关于 forEach
vs 循环的.现在谈谈为什么变量首先需要是最终的,以及为什么你可以对类字段和数组元素这样做.这是因为,正如它所说,Java 有一个限制,即匿名类和 lambda 不能访问局部变量,除非它永远不会改变.这意味着不仅他们自己不能改变它,而且你也不能在他们之外改变它.但这仅适用于局部变量,这就是它适用于类字段或数组元素等其他所有内容的原因.
That was about forEach
vs loops. Now on the topic of why the variable needs to be final in the first place, and why you can do that to class fields and array elements. It's because, like it says, Java has the limitation that anonymous classes and lambdas can't access a local variable unless it never changes. Meaning not only they can't change it themselves, but you can't change it outside them as well. But that only applies to local variables, which is why it works for everything else like class fields or array elements.
我认为这种限制的原因是生命周期问题.局部变量仅在包含它的块正在执行时才存在.多亏了垃圾收集,当有对它的引用时,其他一切都存在.并且其他所有内容也包括 lambdas 和匿名类,因此如果它们可以修改具有不同生命周期的局部变量,则可能会导致类似于 C++ 中的悬空引用的问题.所以 Java 采取了简单的方法:它只是在创建 lambda/匿名类时复制局部变量.但是,如果您可以更改该变量,那将导致混乱(因为副本不会更改,并且由于副本是不可见的,因此会非常混乱).所以 Java 只是禁止对这些变量进行任何更改,仅此而已.
The reason for this limitation, I think, is lifetime issues. A local variable exists only while the block containing it is executing. Everything else exists while there are references to it, thanks to garbage collection. And that everything else includes lambdas and anonymous classes too, so if they could modify local variables which have different lifetime, that could lead to problems similar to dangling references in C++. So Java took the easy way out: it simply copies the local variable at the time the lambda / anonymous class is created. But that would lead to confusion if you could change that variable (because the copy wouldn't change, and since the copy is invisible it would be very confusing). So Java just forbids any changes to such variables, and that's that.
关于最终变量和匿名类已经讨论过很多问题,例如 这个.
There are many questions on the final variables and anonymous classes discussed already, like this one.
相关文章