Java 流和惰性求值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21219667/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stream and lazy evaluation
提问by xdevel2000
I'm reading from the java 8 APIon the stream abstraction but I don't understand this sentence very well:
我正在阅读有关流抽象的java 8 API,但我不太明白这句话:
Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.
中间操作返回一个新的流。他们总是很懒惰;执行诸如 filter() 之类的中间操作实际上并不执行任何过滤,而是创建一个新流,该流在遍历时包含与给定谓词匹配的初始流的元素。管道源的遍历直到管道的终端操作被执行后才开始。
When a filter operation creates a new stream does that stream contains filtered element? It seems to understand that the stream contains elements only when it is traversed i.e with a terminal operation. But, than, what does contains the filtered stream? I'm confused!!!
当过滤操作创建新流时,该流是否包含过滤元素?似乎理解流仅在它被遍历时才包含元素,即使用终端操作。但是,比,什么包含过滤后的流?我糊涂了!!!
采纳答案by assylias
It means that the filter is only applied during the terminal operation. Think of something like this:
这意味着过滤器仅在终端操作期间应用。想想这样的事情:
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;
}
(That does not compile and is a simplification of the reality but the principle is there)
(那不编译,是对现实的简化,但原理在那里)
回答by Nisarg Patil
Streams are lazy because intermediate operations are not evaluated unless terminal operation is invoked.
流是惰性的,因为除非调用终端操作,否则不会评估中间操作。
Each intermediate operation creates a new stream, stores the provided operation/function and return the new stream.
每个中间操作都会创建一个新流,存储提供的操作/函数并返回新流。
The pipeline accumulates these newly created streams.
管道累积这些新创建的流。
The time when terminal operation is called, traversal of streams begins and the associated function is performed one by one.
调用终端操作的时候,开始遍历流,并一一执行相关的功能。
Parallel streams don't evaluate streams 'one by one' (at terminal point). The operations are rather performed simultaneously, depending on the available cores.
并行流不会“一一”评估流(在终点)。这些操作是同时执行的,具体取决于可用的内核。
回答by Андрей Палкин
It seems to me, that intermediate operation not exactly lazy:
在我看来,中间操作并不完全是懒惰的:
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());
}
Otput:
输出:
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
Looks like number of iteration sets on stream creation, but geting a new stream element lazy.
看起来像流创建时的迭代集数,但获得了一个新的流元素懒惰。
Compare to loop with counter:
与计数器循环比较:
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();
}
}
Output:
输出:
1
Only one expected iteration. I agree that problem in Exception throwing behavior in streams, but i think lazy means get data (or perform some action) only when i ask some object to do it; and count of data is also data.
只有一次预期的迭代。我同意流中异常抛出行为的问题,但我认为懒惰意味着只有当我要求某个对象去做时才获取数据(或执行某些操作);并且数据的计数也是数据。