【问题标题】:Java 8 eagerly get the result of an intermediate stream operationJava 8 急切地获取中间流操作的结果
【发布时间】:2015-05-16 03:27:40
【问题描述】:

给定以下代码:

List<String> list = Arrays.asList("a", "b", "c");
        list.stream()
        .map(s -> s + "-" + s)                 //"a-a", "b-b", "c-c"
        .filter(s -> !s.equals("b-b"))         //"a-a", "c-c"
        .forEach(s -> System.out.println(s));

map 和 filter 是中间操作,forEach 是终端操作。只有在终端操作执行后,我们才能得到数据转换的结果。

有没有办法强制评估更加急切并获得某种中间结果 - 而不会破坏流操作链?例如,我想要“a-a”、“b-b”、“c-c”的列表(这将是第一个中间操作的结果)。

【问题讨论】:

  • 你不能peekmap 和filter 之间的流吗? map(...).peek(targetList::add).filter(...)。当然,如果流是并行的,你需要使用线程安全列表。
  • 您可以将它们收集()到一个列表或将它们排列到一个数组中,然后启动一个新的管道。从功能上讲,这正是您想要的。它不是 same 流管道,但这完全是一种审美上的反对。

标签: java java-8 java-stream


【解决方案1】:

你可以使用peek:

List<String> allPairs = new ArrayList<>();
List<String> list = Arrays.asList("a", "b", "c");
    list.stream()
    .map(s -> s + "-" + s)                 //"a-a", "b-b", "c-c"
    .peek(allPairs::add)
    .filter(s -> !s.equals("b-b"))         //"a-a", "c-c"
    .forEach(s -> System.out.println(s));

这样计算在终端操作之前仍然不会开始,但你可以在任何时候“拦截”流内容并以你喜欢的任何方式使用它。

但请注意,如果您的终端操作是短路的(例如 findFirst):这样并非所有元素都可能传递给 peek。

【讨论】:

    【解决方案2】:

    嗯...如果我正确理解您的问题,您必须先应用终端操作,然后再通过 not equals "b-b" 谓词进行过滤。然后,您应该在 intermediate 结果上调用 .stream() 并进行过滤:

    List<String> list = Arrays.asList("a", "b", "c");
    list.stream()
        .map(s -> s + "-" + s)           //"a-a", "b-b", "c-c"
        .collect(Collectors.toList())    //intermediate result
        .stream()
        .filter(s -> !s.equals("b-b"))   //"a-a", "c-c"
        .forEach(s -> System.out.println(s));
    

    【讨论】:

    • 嗯,它的方向是正确的,但我希望将中间结果分配给某些东西。也许最好的方法是使用中间的collect 和我自己的Collector 实现
    • 是的,我只是建议这样做。自定义收藏家是您的朋友。 :)
    【解决方案3】:

    正如 Anton 和 kocko 已经说过的,您可以添加自己的收集器,或者将 Stream.collect 方法与供应商、累加器和组合器参数一起使用:

        List<String> intermediateList = new ArrayList<>();
        List<String> list = Arrays.asList("a", "b", "c");
        list.stream().map(s -> s + "-" + s) // "a-a", "b-b", "c-c"
                .collect(() -> intermediateList, // supplier returns your intermediateList
                        (l, x) -> l.add(x), // accumulator - adds the element to your list
                        (l1, l2) -> {} // l1 and l2 are the same list, i guess - nothing to combine
                ) 
                .stream().filter(s -> !s.equals("b-b")) // "a-a", "c-c"
                .forEach(s -> System.out.println(s));
    

    【讨论】:

      猜你喜欢
      • 2021-02-17
      • 1970-01-01
      • 1970-01-01
      • 2013-05-28
      • 1970-01-01
      • 2016-10-09
      • 1970-01-01
      • 1970-01-01
      • 2014-08-09
      相关资源
      最近更新 更多