在包的javaodoc 中stream,在本节的末尾Parallelism,我读到:
大多数流操作接受描述用户指定行为的参数,这些参数通常是 lambda 表达式。为了保持正确的行为,这些行为参数必须是无干扰的,并且在大多数情况下必须是无状态的。
我很难理解这个“在大多数情况下”。在哪些情况下可以接受/需要有状态的流操作?
我的意思是,我知道这是可能的,特别是在使用顺序流时,但同一个 javadoc 明确指出:
除了明确标识
findAny()为非确定性的操作,例如,流是顺序执行还是并行执行不应改变计算结果。
并且:
另请注意,尝试从行为参数访问可变状态会给您带来安全和性能方面的错误选择;[...] 最好的方法是避免有状态的行为参数完全流式传输操作;通常有一种方法可以重构流管道以避免有状态。
所以,我的问题是:在哪种情况下使用有状态的流操作是一个好习惯(而不是用于副作用工作的方法,例如forEach)?
一个相关的问题可能是:为什么有副作用的操作,例如forEach?我总是最终做一个很好的旧for循环,以避免在我的 lambda 表达式中产生副作用。
我想得到一个答案,指出下面在一个非常简单的例子中描述的以下想法通常被认为是坏的并且知道它的弱点的原因.
我有一句话,我的目标是让每一秒都变成大写.我对这两个案例的出发点完全相同:
String sentence = "Hi, this is just a simple short sentence";
String[] split = sentence.split(" ");
Run Code Online (Sandbox Code Playgroud)
在传统和程序的做法是:
StringBuilder stringBuilder = new StringBuilder();
for (int i=0; i<split.length; i++) {
if (i%2==0) {
stringBuilder.append(split[i]);
} else {
stringBuilder.append(split[i].toUpperCase());
}
if (i<split.length-1) { stringBuilder.append(" "); }
}
Run Code Online (Sandbox Code Playgroud)
当想要使用java-stream时,由于lambda表达式中使用的有效final或final变量约束,使用受到限制.我必须使用数组及其第一个也是唯一的索引来解决这个问题,我在问题的第一个评论中建议如何在Java Stream中增加一个值.这是一个例子:
int index[] = {0};
String result = Arrays.stream(split)
.map(i -> index[0]++%2==0 ? i : i.toUpperCase())
.collect(Collectors.joining(" "));
Run Code Online (Sandbox Code Playgroud)
是的,这是一个糟糕的解决方案,我听到一些隐藏在我无法找到的问题评论中的好理由(如果你提醒我其中一些,如果可能的话我会投票两次).但是,如果我使用AtomicInteger它会产生什么影响呢?它是一种安全好的方式,与前一种相比没有副作用吗?
AtomicInteger atom = new AtomicInteger(0);
String …Run Code Online (Sandbox Code Playgroud)