我正在尝试使用 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 - 同一管道中已排序流的 Stream takeWhile,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58665470/

10-12 21:49