【问题标题】:Sequential streams and shared state顺序流和共享状态
【发布时间】:2015-08-02 01:03:59
【问题描述】:

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() 中的表达式使用了一些共享状态。我们可以相信它在使用顺序流时可以正常工作吗?

【问题讨论】:

  • 我不会相信任何操纵状态的东西。尽可能避免它。

标签: java java-8 java-stream


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    如果您依赖 forEach 顺序执行,请考虑使用 forEachOrdered 代替,即使流是顺序的。这不仅会从 api 中得到明确的保证,即代码将按顺序执行,它还会使代码更具自我记录性,并提供一些保护措施,防止有人出现并将您的流更改为并行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      相关资源
      最近更新 更多