问题描述
如何检查流实例是否已被使用(意味着已经调用了终端操作,使得对终端操作的任何进一步调用都可能因IllegalStateException: stream has already been operated upon or closed.
而失败?
How can I check if a stream instance has been consumed or not (meaning having called a terminal operation such that any further call to a terminal operation may fail with IllegalStateException: stream has already been operated upon or closed.
?
理想情况下,我想要一个不消耗流的方法,如果尚未消耗流,则返回一个布尔值false(如果流被消耗而没有从流方法捕获IllegalStateException
)(因为使用Exceptions作为控制权)流程昂贵且容易出错,尤其是在使用标准Exceptions时.)
Ideally I want a method that does not consume the stream if it has not yet been consumed, and that returns a boolean false if the stream has been consumed without catching an IllegalStateException
from a stream method (because using Exceptions for control flow is expensive and error prone, in particular when using standard Exceptions).
与Iterator中的hasNext()
相似的方法,它具有异常抛出和布尔返回行为(尽管没有与next()
签订合同).
A method similar to hasNext()
in Iterator in the exception throwing and boolean return behavior (though without the contract 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");
}
}
目标是如果客户端代码在不消耗流的情况下调用此方法,则会尽早失败.
The goal is to fail early if client code calls this method without consuming the stream.
似乎没有办法做到这一点,我必须添加一个try-catch块来调用诸如iterator()
之类的任何终端操作,捕获异常并抛出新异常.
It seems there is no method to do that and I'd have to add a try-catch block calling any terminal operation like iterator()
, catch an exception and throw a new one.
一个可以接受的答案也可以是没有解决方案",并且有充分的理由说明为什么规范不能添加这种方法(如果存在充分的理由).似乎JDK流通常在其终端方法的开头具有以下代码段:
An acceptable answer can also be "No solution exists" with a good justification of why the specification could not add such a method (if a good justification exists). It seems that the JDK streams usually have this snippets at the start of their terminal methods:
// in AbstractPipeline.java
if (linkedOrConsumed)
throw new IllegalStateException(MSG_STREAM_LINKED);
因此对于这些流,实现这种方法似乎并不那么困难.
So for those streams, an implementation of such a method would not seem that difficult.
推荐答案
考虑到spliterator
(例如)是终端操作,您可以简单地创建一个方法,例如:
Taking into consideration that spliterator
(for example) is a terminal operation, you can simply create a method like:
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()));
}
我不知道有什么更好的方法...而用法是:
I don't know of a better way to do it... And usage would be:
Stream<Integer> ints = Stream.of(1, 2, 3, 4)
.filter(x -> x < 3);
YourClass.isConsumed(ints)
.ifPresent(x -> x.forEachOrdered(System.out::println));
由于我认为不存在返回已消耗的Stream的实际原因,因此我将返回Optional.empty()
.
Since I don't think there is a practical reason to return an already consumed Stream, I am returning Optional.empty()
instead.
这篇关于检查是否已消耗Java流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!