【发布时间】:2016-05-07 06:04:50
【问题描述】:
我的问题很简单。 Java 流上的中间限制和跳过操作被标记为有状态操作 - 我假设是因为它们默认需要限制或跳过有序流上的前 n 个元素。
如果我通过调用 unordered() 方法或使用无序源使输入源流无序,我们是否可以有效地说这些操作可以被认为是无状态的,或者我在这里遗漏了什么?
【问题讨论】:
标签: java java-stream stateless stateful
我的问题很简单。 Java 流上的中间限制和跳过操作被标记为有状态操作 - 我假设是因为它们默认需要限制或跳过有序流上的前 n 个元素。
如果我通过调用 unordered() 方法或使用无序源使输入源流无序,我们是否可以有效地说这些操作可以被认为是无状态的,或者我在这里遗漏了什么?
【问题讨论】:
标签: java java-stream stateless stateful
不,limit 和 skip 仍然是有状态的操作,因为元素的处理取决于其他元素的处理信息(即它们是否已被处理)。
对于无序流,这些操作更容易实现,但这不会改变它们的状态性质。
您可以通过简单地问自己来判断这一点:“是否可以通过仅查看元素而不其他任何内容(除了在启动整个流操作之前已知的不变信息)来为单个元素实现此操作?”
【讨论】:
我假设您的问题是关于并行流,因为在当前 Stream API 实现中顺序流不以任何方式使用排序。
当前并行无序skip/limit 实现对每个并行任务使用大小为 128 的缓冲区,因此您可能会从源中读取比实际需要更多的元素。这样做是为了减少对共享原子变量的可能争用,这可能对低 Q 任务(每个元素处理非常快的任务)至关重要。所以要回答你的问题,不,无序的skip/limit 操作仍然是有状态的。
您可以使用以下程序轻松检查:
AtomicLong counter = new AtomicLong();
IntStream.range(0, 1_000_000).parallel().unordered().filter(x -> true)
.peek(x -> counter.incrementAndGet()).limit(1000).toArray();
System.out.println(counter.get());
它会打印实际从源中获取的元素数量。在我的四核系统上,此代码通常打印 1280 (128*10) 或 1408 (128*11),即使请求了 1000 个元素。
【讨论】:
findFirst() 和findAny() 是一样的。还有forEach 和forEachOrdered。并且distinct() 在顺序模式下对无序流没有任何优势(尽管为distinct() 保留顺序似乎没有开销)。