顺序流和共享状态

时间:2015-08-02 01:03:59

标签: java java-8 java-stream

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()有点模糊。最后,作者将代码更改为使用ConcurrentHashMapmap.putIfAbsent()

我的问题是:我是否正确紧张,或者上面的代码值得信赖吗?

假设filter()中的表达式做了一些使用某些共享状态的表达式。我们可以相信它在使用顺序流时可以正常工作吗?

2 个答案:

答案 0 :(得分:2)

顺序流按定义执行调用程序线程中的所有内容,因此,如果您将来不打算并行化您的流,则可以安全地使用共享状态而无需额外的同步和并发安全集合。所以当前的代码是安全的。但请注意,它看起来很脏。

答案 1 :(得分:1)

如果您依赖forEach顺序执行,请考虑使用forEachOrdered,即使流是连续的。这不仅可以从API获得明确的保证,即代码将按顺序执行,它将使代码更加自我记录,并提供一些保护措施,防止有人出现并将您的流更改为并行。