【问题标题】:Intermediate operation in Java streams [duplicate]Java流中的中间操作[重复]
【发布时间】:2019-02-04 04:52:47
【问题描述】:

在 java 8 中,我使用 Streams 打印输出,但大小为 0。为什么?

public class IntermediateryAndFinal {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("one", "two", "three", "four", "five");

        Predicate<String> p1 = Predicate.isEqual("two");
        Predicate<String> p2 = Predicate.isEqual("three");

        List<String> list = new ArrayList<>();

        stream.peek(System.out::println)
            .filter(p1.or(p2))
            .peek(list::add);
        System.out.println("Size = "+list.size());
    }
}

【问题讨论】:

    标签: java collections java-8 java-stream


    【解决方案1】:

    理想情况下,您不应该改变外部列表,而是可以使用Collectors.toList() 将其收集到列表中:

    List<String> list = stream.peek(System.out::println)
                .filter(p1.or(p2))
                .collect(Collectors.toList()); // triggers the evaluation of the stream
    System.out.println("Size = "+list.size());
    

    在您的示例中,只有在终端操作

    时才会评估流
    allMatch()
    anyMatch() 
    noneMatch() 
    collect() 
    count() 
    forEach() 
    min() 
    max() 
    reduce()
    

    遇到了。

    【讨论】:

      【解决方案2】:

      由于您尚未完成流操作,即peek 是一个中间操作。您必须使用 终端操作 才能继续执行。

      建议:改为使用collect等终端操作进行此类操作

      List<String> list = stream.peek(System.out::println)
              .filter(p1.or(p2))
              .collect(Collectors.toList());
      

      另外:添加peek 帖子filter 来观察值可能有点难以观察,如下代码

      List<String> list = stream.peek(System.out::println)
              .filter(p1.or(p2))
              .peek(System.out::println) // addition
              .collect(Collectors.toList());
      

      输出看起来像:

      one
      two
      two // filtered in
      three
      three // filtered in
      four
      five
      

      【讨论】:

        【解决方案3】:

        流是懒惰的。你可以调用类似forEach的终端操作:

        stream.peek(System.out::println)
              .filter(p1.or(p2))
              .forEach(list::add);
        

        如果您想使用peek 作为中间操作进行调试,那么您必须在之后调用终端操作:

        stream.peek(System.out::println)
              .filter(p1.or(p2))
              .peek(list::add);
              .<any terminal operation here>();
        

        顺便说一句,如果您只想将所有过滤后的值存储在一个列表中,那么最好使用collect(toList())

        【讨论】:

        • 在终端操作(forEach)中应避免诸如修改数据结构之类的操作,在后一种方法中,有可能不执行 peek,例如count()的Java-9及以上实现。
        • @nullpointer 确实如此。我在回答 OP 的问题 “为什么?”。所以答案就在第一行。但当然,我总是建议在处理流时避免状态突变。
        【解决方案4】:

        您对filterpeek 所做的所有工作都是设置一系列操作以应用于流。您实际上还没有使它们中的任何一个运行。您必须添加一个终端操作,例如count。 (另一个答案建议使用forEach 添加到列表中,但我认为您专门尝试使用中间操作peek。)

        【讨论】:

        猜你喜欢
        • 2016-05-06
        • 2020-10-07
        • 1970-01-01
        • 2022-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多