java - 流 takeWhile 用于同一管道中的排序流

标签 java java-stream java-9

我正在尝试使用 java9 的 takeWhile 过滤排序流,以从流的开头获取共享相同字段值的对象。我无法编写正确的谓词来执行此操作。这可以通过破坏流管道的两个步骤来完成。

Stream.of(objA, objB, objC, objD, objE, objF, objG)
    .takeWhile(" get the value of objA´s field and take 
   as long as as other objects value for that field is the same as objA´s");

分两步我可以做类似的事情

int x = Stream.of(objA, objB, objC, objD, objE, objF, objG).findFirst().get().getSomeValue();

Stream.of(objA, objB, objC, objD, objE, objF, objG).takeWhile(e -> e.getSomeValue() == x);

一个简化的例子可以是

Stream.of(5,5,5,5,13,14,5,5,2,5,5,6)
.takeWhile(get the first four '5'´s)

可以在不使用Optional.get中间步骤的情况下完成此操作吗?

最佳答案

一个(有点笨拙)的解决方法是使用包含 null 或第一个值的可变持有者对象(因为引用必须是 effectively final )。我们将在此示例中使用 AtomicReference

AtomicReference<MyClass> holder = new AtomicReference<>();

sortedStream.takeWhile(e -> holder.get() == null || holder.get().equals(e))
.map(e -> { holder.set(e); return e; })
.collect(Collectors.toList());

现在这仍然包含一个额外的步骤,但由于 Stream 只能处理一次,因此 findFirst() 方法无论如何都不起作用。即使已经设置了持有者对象,这也会继续设置它,但这只是一个小烦恼而不是问题。

正如 Holger 指出的,一个更好、更精简的版本将是

sortedStream.takeWhile(e -> holder.compareAndSet(null, e.getSomeValue()) || e.getSomeValue() == holder.get())
.collect(Collectors.toList());

其中第一个元素 compareAndSet 分配值,返回 true,随后的元素将与持有者的值进行比较。

如果您确实使用这种方法,我建议添加指向此问题/答案的注释,或者至少以某种方式尝试解释此代码实现的功能,因为对于阅读代码的人来说,这可能不会立即显而易见。

关于java - 流 takeWhile 用于同一管道中的排序流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58665470/

相关文章:

java - Java 中 lambda () -> { } 的含义

Java 并行流只使用一个线程?

java - 如何使用 java.net.http.HttpClient 记录请求/响应?

java - 包含流的 takeWhile()

java - 我需要一个只有一个实现的接口(interface)吗?

java - 双倍流

java - 当计数 > 100 时进行分组 Java Stream

java - JodaTime - 检查 LocalTime 是否在现在之后和现在在另一个 LocalTime 之前

java - 具有 inter_word justificationMode 的可选 TextView

java - 我不明白为什么我的 if 语句有效