溪流如何停止? [英] How do streams stop?
问题描述
我想知道当我使用 Stream.generate
创建自己的无限流时,标准库中的Streams如何停止...
例如,如果您有一个包含记录的列表:
List< Record> records = getListWithRecords();
records.stream()。forEach(/ *做某事* /);
流不会无限并且永远在运行,但是当列表中的所有项目都会停止遍历。但是这有什么作用呢?相同的功能适用于由 Files.lines(path)
创建的流(来源: http://www.mkyong.com/java8/java-8-stream-read-a-file-line-by -line / )。
第二个问题,如何使用 Stream.generate
然后以相同的方式停止?
有限流不是通过 Stream创建的。生成
。
实现流的标准方法是实现 Spliterator
,有时使用 Iterator
绕道。在任何一种情况下,实现都有一种报告结束的方法,例如当 Spliterator.tryAdvance
返回 false
或其 forEachRemaining
方法时返回,或者在 Iterator
来源的情况下,当 hasNext()
返回 false
。
A Spliterator
甚至可以在处理开始前报告预期的元素数量。 / p>
Streams,通过 Stream
界面中的一种工厂方法创建,如 Stream。生成
也可以通过 Spliterator
或使用流实现的内部功能来实现,但不管它们是如何实现的,不要让这个实现改变他们的行为,所以使这样的流有限的唯一方法是将限制
操作链接到流。
如果你想创建一个没有数组或集合支持的非空有限流,并且没有现有的流源适合,你有实现自己的 Spliterator
和从中创建一个流。如上所述,您可以使用现有方法从 Iterator
中创建 Spliterator
,但是您应该抵制诱惑使用 Iterator
只是因为它很熟悉。 Spliterator
并不难实现:
/ ** like { @code Stream.generate},但具有内在限制* /
static< T>流< T>生成(供应商< T> s,长计数){
返回StreamSupport.stream(
new Spliterators.AbstractSpliterator< T>(count,Spliterator.SIZED){
long remaining = count;
public boolean tryAdvance(Consumer<?super T> action){
if(remaining< = 0)if false;
remaining--;
action.accept( s.get());
返回true;
}
},false);
}
从这个起点开始,你可以为默认
Spliterator
界面的方法,加权开发费用和潜在的性能改进,例如
static< T>流< T>生成(供应商< T> s,长计数){
返回StreamSupport.stream(
new Spliterators.AbstractSpliterator< T>(count,Spliterator.SIZED){
long remaining = count;
public boolean tryAdvance(Consumer<?super T> action){
if(remaining< = 0)if false;
remaining--;
action.accept( s.get());
返回true;
}
/ **可以改善大多数非短路操作的性能* /
@Override
public void forEachRemaining(Consumer<?super T> action){
long toGo =剩余;
剩余= 0;
for(; toGo> 0; toGo--)操作.accept(s.get());
}
},false);
}
I was wondering when I created my own infinite stream with Stream.generate
how the Streams which are in the standard library stop...
For example when you have a list with records:
List<Record> records = getListWithRecords();
records.stream().forEach(/* do something */);
The stream won't be infinite and running forever, but it will stop when all items in the list are traversed. But how does that work? The same functionality applies for the stream created by Files.lines(path)
(source: http://www.mkyong.com/java8/java-8-stream-read-a-file-line-by-line/).
And a second question, how can a stream created with Stream.generate
be stopped in the same manner then?
Finite streams simply aren’t created via Stream.generate
.
The standard way of implementing a stream, is to implement a Spliterator
, sometimes using the Iterator
detour. In either case, the implementation has a way to report an end, e.g. when Spliterator.tryAdvance
returns false
or its forEachRemaining
method just returns, or in case of an Iterator
source, when hasNext()
returns false
.
A Spliterator
may even report the expected number of elements before the processing begins.
Streams, created via one of the factory methods inside the Stream
interface, like Stream.generate
may be implemented either, by a Spliterator
as well or using internal features of the stream implementation, but regardless of how they are implemented, you don’t get hands on this implementation to change their behavior, so the only way to make such a stream finite, is to chain a limit
operation to the stream.
If you want to create a non-empty finite stream that is not backed by an array or collection and none of the existing stream sources fits, you have to implement your own Spliterator
and create a stream out of it. As told above, you can use an existing method to create a Spliterator
out of an Iterator
, but you should resists the temptation to use an Iterator
just because it’s familiar. A Spliterator
is not hard to implement:
/** like {@code Stream.generate}, but with an intrinsic limit */
static <T> Stream<T> generate(Supplier<T> s, long count) {
return StreamSupport.stream(
new Spliterators.AbstractSpliterator<T>(count, Spliterator.SIZED) {
long remaining=count;
public boolean tryAdvance(Consumer<? super T> action) {
if(remaining<=0) return false;
remaining--;
action.accept(s.get());
return true;
}
}, false);
}
From this starting point, you can add overrides for the default
methods of the Spliterator
interface, weighting development expense and potential performance improvements, e.g.
static <T> Stream<T> generate(Supplier<T> s, long count) {
return StreamSupport.stream(
new Spliterators.AbstractSpliterator<T>(count, Spliterator.SIZED) {
long remaining=count;
public boolean tryAdvance(Consumer<? super T> action) {
if(remaining<=0) return false;
remaining--;
action.accept(s.get());
return true;
}
/** May improve the performance of most non-short-circuiting operations */
@Override
public void forEachRemaining(Consumer<? super T> action) {
long toGo=remaining;
remaining=0;
for(; toGo>0; toGo--) action.accept(s.get());
}
}, false);
}
这篇关于溪流如何停止?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!