[英]Stream and lazy evaluation
我正在阅读有关流抽象的java 8 API ,但我不太明白这句话:
中间操作返回一个新的流。 他们总是很懒惰; 执行诸如 filter() 之类的中间操作实际上并不执行任何过滤,而是创建一个新流,该流在遍历时包含与给定谓词匹配的初始流的元素。 管道源的遍历直到管道的终端操作被执行后才开始。
当过滤操作创建新流时,该流是否包含过滤元素? 它似乎理解流仅在它被遍历时才包含元素,即使用终端操作。 但是,比,什么包含过滤后的流? 我糊涂了!!!
这意味着过滤器仅在终端操作期间应用。 想想这样的事情:
public Stream filter(Predicate p) {
this.filter = p; // just store it, don't apply it yet
return this; // in reality: return a new stream
}
public List collect() {
for (Object o : stream) {
if (filter.test(o)) list.add(o);
}
return list;
}
(那不编译,是对现实的简化,但原理在那里)
流是惰性的,因为除非调用终端操作,否则不会评估中间操作。
每个中间操作都会创建一个新流,存储提供的操作/函数并返回新流。
管道累积这些新创建的流。
调用终端操作的时候,开始遍历流,并一一执行相关的功能。
并行流不会“一一”评估流(在终点)。 这些操作是同时执行的,具体取决于可用的内核。
在我看来,中间操作并不完全是懒惰的:
List<String> l3 = new ArrayList<String>();
l3.add("first");
l3.add("second");
l3.add("third");
l3.add("fouth");
l3.add("fith");
l3.add("sixth");
List<String> test3 = new ArrayList<String>();
try {
l3.stream().filter(s -> { l3.clear(); test3.add(s); return true;}).forEach(System.out::println);
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("!!! ");
System.out.println(test3.stream().reduce((s1, s2) -> s1 += " ;" + s2).get());
}
输出:
first
null
null
null
null
null
java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1380)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at test.TestParallel.main(TestParallel.java:69)
!!!
first ;null ;null ;null ;null ;null
看起来像流创建时的迭代集数,但获得了一个新的流元素懒惰。
与计数器循环比较:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
int i = 0;
while (i < list.size()) {
System.out.println(list.get(i++));
list.clear();
}
}
输出:
1
只有一次预期的迭代。 我同意流中异常抛出行为的问题,但我认为懒惰意味着只有当我要求某个对象去做时才获取数据(或执行某些操作); 并且数据的计数也是数据。
这意味着过滤器仅在终端操作期间应用。
让我们看看中间操作是如何懒惰的? 我们有一个map()函数,我们在其中打印当前的学生姓名。 只有在我们应用终端运营商时才会打印这些名称。 在下面的示例中,我们应用了collect(终端运算符),map()在线程进入运行状态后打印学生名称。 这就是中间操作的工作原理。
private static void lazyIntermediateOperations(List<Student> students) throws InterruptedException {
System.out.println("######## Executing lazyIntermediateOperations() : ######## ");
Stream<String> studentStream = students.stream()
.map(student -> {
System.out.printf("In Map : %s\n", student.getName());
return student.getName().toUpperCase();
});
System.out.println("After map statement");
Thread.sleep(5000);
System.out.println("Thread is in Running state now");
studentStream.collect(Collectors.toList());
System.out.println("######## Ending the execution of lazyIntermediateOperations() ######## ");
}
输出继电器
##执行lazyIntermediateOperations():########地图声明后
线程现在处于Running状态
在地图:Saurabh在地图:罗伯特在地图:约翰在地图:罗马在地图:兰迪
##结束lazyIntermediateOperations()的执行有关更多信息,请参阅以下链接: https : //onlyfullstack.blogspot.com/2018/12/intermediate-and-terminal-operations-in-java-8.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.