我正在阅读流抽象的java 8 API但是 我不太理解这句话:
中间操作返回一个新流。他们总是懒惰; 执行诸如filter()之类的中间操作实际上并不是这样 执行任何过滤,而是创建一个新的流,当时 遍历,包含匹配的初始流的元素 给出谓词。直到管道源的遍历才开始 执行管道的终端操作。
当过滤操作创建新流时,该流是否包含已过滤的元素? 似乎可以理解,流只有在遍历时才包含元素,即终端操作。但是,包含过滤流的内容是什么?我糊涂了!!!
答案 0 :(得分:48)
这意味着过滤器仅在终端操作期间应用。想想这样的事情:
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;
}
(这不是编译,是对现实的简化,但原则就在那里)
答案 1 :(得分:12)
Streams是惰性的,因为除非调用终端操作,否则不会评估中间操作。
每个中间操作都会创建一个新流,存储提供的操作/功能并返回新流。
管道累积这些新创建的流。
调用终端操作的时间,流的遍历开始,相关的功能逐个执行。
并行流不会逐个评估流(在终端点)。根据可用的核心,操作是同时执行的。
答案 2 :(得分:1)
在我看来,中间操作并不完全是懒惰的:
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
看起来像流创建的迭代集数量,但是设置了一个新的流元素lazy。
与循环计数器比较:
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
只有一个预期的迭代。 我同意在流中的异常抛出行为中的问题,但我认为懒惰意味着只有在我要求某个对象执行时才获取数据(或执行某些操作);数据也是数据。
答案 3 :(得分:-1)
这意味着仅在终端操作期间应用过滤器。
让我们看看中间操作是多么懒惰吗? 我们有一个map()函数,在其中打印当前的学生姓名。仅当我们将终端操作符应用于这些名称时,才会打印这些名称。在下面的示例中,我们应用了collect(terminal operator),并且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():########在地图声明之后
线程现在处于运行状态
在地图上:索拉卜 在地图上:罗伯特 在地图上:约翰 在地图上:罗马 在地图上:兰迪
##结束lazyIntermediateOperations()的执行有关更多信息,您可以参考以下链接: https://onlyfullstack.blogspot.com/2018/12/intermediate-and-terminal-operations-in-java-8.html