检查是否已消耗Java流

tkr*_*use 9 java java-stream

我如何检查流实例是否已被使用(意味着已经调用了终端操作,使得对终端操作的任何进一步调用都可能失败IllegalStateException: stream has already been operated upon or closed.

理想情况下,我想要一个不消耗流的方法,如果该流尚未被消耗,则返回一个布尔值false(如果流被消耗而没有IllegalStateException从流方法中捕获)(因为对控制流使用Exception代价很高并且容易出错) ,尤其是在使用标准例外时)。

hasNext()Iterator中类似的方法,它具有异常抛出和布尔返回行为(尽管没有约定to next())。

例:

public void consume(java.util.function.Consumer<Stream<?>> consumer, Stream<?> stream) {
   consumer.accept(stream);
   // defensive programming, check state
   if (...) {
       throw new IllegalStateException("consumer must call terminal operation on stream");
   }
}
Run Code Online (Sandbox Code Playgroud)

目标是如果客户端代码在不消耗流的情况下调用此方法,则会尽早失败。

似乎没有办法做到这一点,我必须添加一个try-catch块来调用任何终端操作,例如iterator(),捕获异常并抛出一个新异常。

可以接受的答案也可以是“不存在解决方案”,其中有充分的理由说明为什么规范无法添加这种方法(如果存在良好的理由)。似乎JDK流通常在其终端方法的开头具有以下代码片段:

// in AbstractPipeline.java
if (linkedOrConsumed)
    throw new IllegalStateException(MSG_STREAM_LINKED);
Run Code Online (Sandbox Code Playgroud)

因此,对于那些流,实现这种方法似乎并不那么困难。

Eug*_*ene 4

考虑到spliterator(例如)是终端操作,您可以简单地创建一个方法,例如:

private static <T> Optional<Stream<T>> isConsumed(Stream<T> stream) {

    Spliterator<T> spliterator;
    try {
        spliterator = stream.spliterator();
    } catch (IllegalStateException ise) {
        return Optional.empty();
    }

    return Optional.of(StreamSupport.stream(
        () -> spliterator,
        spliterator.characteristics(),
        stream.isParallel()));
}
Run Code Online (Sandbox Code Playgroud)

我不知道有更好的方法......用法是:

Stream<Integer> ints = Stream.of(1, 2, 3, 4)
                                 .filter(x -> x < 3);

YourClass.isConsumed(ints)
         .ifPresent(x -> x.forEachOrdered(System.out::println));
Run Code Online (Sandbox Code Playgroud)

由于我认为没有实际原因返回已消耗的 Stream,Optional.empty()因此我将返回。