javadoc for java.util.stream
暗示"行为操作"在流管道中通常必须是无状态的。但是,它显示如何不编写管道的示例似乎都涉及并行流。
这在多大程度上适用于顺序流?
特别是,我正在查看同事的代码,看起来基本上是这样的:
List<SomeClass> list = ...;
Map<SomeClass, String> map = new HashMap<>();
list.stream()
.filter(x -> [some boolean expression])
.forEach(x -> {
if (map.containsKey(x) {
throw new UserDefinedException("duplicates detected in input");
} else {
map.put(x, aStringFunction(x));
}
});
[作者曾尝试使用Collectors.toMap()
,但是当有重复项时,它会抛出IllegalStateException
,而且我们都不知道toMap
需要mergeFunction
。最后一次是最好的解决方案,但无论如何我都想得到一个答案,因为涉及更广泛的原则。]
我对这段代码感到紧张,因为我不清楚forEach
中块的执行是否可能对不同的元素重叠,即使对于顺序流也是如此。对于访问顺序流中的共享状态是否需要同步,javadoc for forEach()
有点模糊。最后,作者将代码更改为使用ConcurrentHashMap
和map.putIfAbsent()
。
我的问题是:我是否正确紧张,或者上面的代码值得信赖吗?
假设filter()
中的表达式做了一些使用某些共享状态的表达式。我们可以相信它在使用顺序流时可以正常工作吗?
答案 0 :(得分:2)
顺序流按定义执行调用程序线程中的所有内容,因此,如果您将来不打算并行化您的流,则可以安全地使用共享状态而无需额外的同步和并发安全集合。所以当前的代码是安全的。但请注意,它看起来很脏。
答案 1 :(得分:1)
如果您依赖forEach
顺序执行,请考虑使用forEachOrdered
,即使流是连续的。这不仅可以从API获得明确的保证,即代码将按顺序执行,它将使代码更加自我记录,并提供一些保护措施,防止有人出现并将您的流更改为并行。