繁体   English   中英

takeWhile,dropWhile laziness java9

[英]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操作之后,除非你迭代剩下的所有元素,否则无法知道结果。

TL; DR

始终查看整个流,尤其是终端操作,以判断管道的行为方式。 collect它会影响打印元素,就像takeWhiledropWhile

详细地

我不确定你是否不同意输出或结果列表。 在任何情况下它既不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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM