[英]takeWhile, dropWhile laziness java9
在scala中,这些方法工作正常,但在java9中,dropWhile的工作方式与我想的不同。
以下是takeWhile的示例
Stream.of("a", "b", "c", "de", "f", "g", "h")
.peek(System.out::println)
.takeWhile(s -> s.length() <= 1)
.collect(Collectors.toList());
输出很好:a,b,c,de,[a,b,c]它不处理“de”之后的元素,所以它按预期工作
但是DropWhile以我期望的不同方式工作:
Stream.of("a", "b", "c", "de", "f", "g", "h")
.peek(s -> System.out.print(s + ", "))
.dropWhile(s -> s.length() <= 1)
.collect(Collectors.toList());
输出为:a,b,c,de,f,g,h,[de,f,g,h]
因此它不会在“de”元素之后停止,它正在处理整个集合。
为什么要处理整个系列? 我知道,需要获取所有元素并将其收集到列表中,但不应该在“de”元素之后停止处理吗?
看来,对于peek
工作方式存在根本性的误解。 它与下一个后续链接操作(如dropWhile
,而是dropWhile
后面的整个Stream管道相关联。 它并没有区分“处理元素”和“占用所有元素”。
所以简单的代码
Stream.of("a", "b", "c", "de", "f", "g", "h")
.peek(System.out::println)
.collect(Collectors.toList());
“获取所有元素”,但在将它们从Stream源传递到收集器时打印它们。
在您的示例中,无论是将元素传递给dropWhile
的谓词还是直接传递给Collector
都没有区别,在任何一种情况下,它都将通过放在两者之前的peek
操作进行报告。
如果你使用
Stream.of("a", "b", "c", "de", "f", "g", "h")
.dropWhile(s -> {
System.out.println("dropWhile: "+s);
return s.length() <= 1;
})
.peek(s -> System.out.println("collecting "+s))
.collect(Collectors.toList());
相反,它会打印出来
dropWhile: a
dropWhile: b
dropWhile: c
dropWhile: de
collecting de
collecting f
collecting g
collecting h
显示dropWhile
的谓词的评估如何在第一个未接受的元素之后停止,而向Collector
的传输以该元素开始。
这不同于takeWhile
其中两个 ,谓词评价和集电极,停止消耗元件,所以没有消费者左和整个流管道可以停止迭代源。
这是预期的行为,与scala中的工作方式相同,dropWhile处理整个流。
dropWhile与takeWhile相反。 takeWhile在条件变为false时停止处理。 dropWhile处理整个流,但只有在条件为真时才传递任何元素。 一旦条件变为false,dropWhile会传递所有剩余元素,无论条件是真还是假。
我可能会在这里说明显而易见的事情,但这对我来说很有意义,所以也可以帮助你。
takeWhile获取前n个元素,直到命中Predicate(它返回true)。 因此,如果您在输入流中说出7个元素,并且takeWhile将为前3个返回true,则生成的流将包含3个元素。
你可以这样思考:
Stream result = Stream.empty();
while(predicate.apply(streamElement)){ // takeWhile predicate
result.add(streamElement);
streamElement = next(); // move to the next element
}
return result;
dropWhile说删除元素直到Predicate被击中(它返回true)。 在删除3个元素之后,结果流会是什么样子? 要知道我们需要迭代所有其他元素,这就是peek报告其余元素的原因。
我也喜欢从Set(而不是List)中dropWhile的类比。 假设这是你的集合:
Set<String> mySet = Set.of("A", "B", "CC", "D");
并且你会用同一个谓词做一个dropWhile(因为它不是List而你没有遇到命令); 在dropWhile操作之后,除非你迭代剩下的所有元素,否则无法知道结果。
始终查看整个流,尤其是终端操作,以判断管道的行为方式。 collect
它会影响打印元素,就像takeWhile
或dropWhile
。
我不确定你是否不同意输出或结果列表。 在任何情况下它既不takeWhile
也不dropWhile
正在处理流,但该终端操作时, collect
在这种情况下。 它的任务是收集流中的所有元素,从而“拉”元素,直到流报告不再包含元素。
一旦条件第一次变为false
,就是takeWhile
的情况。 在报告没有剩余元素之后,collect停止拉动元素,因此输入流的处理停止,并且来自peek
的消息也停止。
但它与dropWhile
不同。 在第一次请求时,它通过输入流“快进”直到条件第一次变为false
(这使得peek
打印a, b, c, de
。它看到的任何操作的第一个元素是de
。从那时起, collect
继续通过流拉动元素,直到它被报告为空,这是输入流以h
结束h
,这导致其余的输出从peek
。
尝试使用以下内容,这应该导致a, b, c, de [de]
。 (我很确定,我甚至都没试过。;))
Stream.of("a", "b", "c", "de", "f", "g", "h")
.peek(s -> System.out.print(s + ", "))
.dropWhile(s -> s.length() <= 1)
.findFirst();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.