Lea*_*ner 19 java-8 java-stream
我正在阅读Java 8,特别是"Streams API".我想知道流是如何懒惰的?
我相信流只是作为一个库添加,并且没有对语言进行任何更改来支持懒惰.另外,如果有人告诉我这是通过反思实现的,我会感到震惊.
Ale*_* C. 23
为什么你需要反思才能得到懒惰?例如,考虑这个类:
class LazySeq<T> {
private final List<T> list;
private Predicate<? super T> predicate;
public LazySeq(List<T> input) {
this.list = new ArrayList<>(input);
}
//Here you just store the predicate, but you don't perform a filtering
//You could also return a new LazySeq with a new state
public LazySeq<T> filter(Predicate<? super T> predicate) {
this.predicate = predicate;
return this;
}
public void forEach(Consumer<? super T> consumer){
if(predicate == null) {
list.forEach(consumer);
} else {
for(T elem : list) {
if(predicate.test(elem)) {
consumer.accept(elem);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
当您调用filterlazy seq时,过滤不会立即发生,例如:
LazySeq<Integer> lazySeq = new LazySeq<>(Arrays.asList(1, 2, 3, 4));
lazySeq = lazySeq.filter(i -> i%2 == 0);
Run Code Online (Sandbox Code Playgroud)
如果在调用filter后看到序列的内容,你会发现它始终是1, 2, 3, 4.但是,当调用终端操作时,例如forEach,过滤将在使用消费者之前完成.例如:
lazySeq.filter(i -> i%2 == 0).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
将打印2和4.
这与Streams的原理相同.从源中,链接具有某些属性的操作.这些操作要么是中间的,要么返回惰性流(例如filter或map),要么返回终端(例如forEach).其中一些终端操作是短路的(例如findFirst),因此您可能无法遍历所有管道(例如,您可以考虑在for循环中返回数组索引的早期返回).
当调用终端操作时,这一系列操作开始执行,以便最后得到预期的结果.
当应用中间操作时,可以通过在管道上存储新状态来实现惰性,当您调用终端操作时,您可以逐个访问数据上的所有状态.
Stream API并没有真正实现(它有点复杂),但实际上原理就在这里.
没有反思或代理.反思和代理带来了应该避免的性能成本,除非没有替代方案且性能是第一位的Java.
使懒惰成为可能的是做事的功能风格.基本上是以stream源(ex:List),中间操作数(例如:filters,map ..)和终端操作(例如:count,sum等)开始.中间步骤执行延迟,因为您传递了在管道中链接的函数(lambdas),以便在终端步骤执行.
ex: filter(Predicate<? super T>)
Run Code Online (Sandbox Code Playgroud)
filter 在此示例中,需要一个函数来告诉我们流中的对象是否满足某些条件.
Java 7中提供了许多功能,可以提高效率.例如:调用动态来执行lambdas而不是代理或匿名内部类和ForkJoin池来执行并行执行.
如果你对Java 8内部感兴趣,那么你必须看看Brian Goetz领域的专家给出的这个演讲,它在Youtube上.
| 归档时间: |
|
| 查看次数: |
5573 次 |
| 最近记录: |