Java 8 热切获取中间流操作的结果

5

给定以下代码:

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));

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

是否有办法强制计算变得更加迫切,并且拥有某种类型的中间结果 - 而不破坏流操作链?例如,我想要 "a-a"、"b-b"、"c-c" 的列表(这将是第一个中间操作的结果)。


1
你不能在 mapfilter 之间 peek 流吗?map(...).peek(targetList::add).filter(...)。当然,如果流被并行处理,你需要使用线程安全的列表。 - Alexis C.
2
你可以使用collect()方法将它们收集到一个列表中,或者使用toArray()方法将它们转换为数组,然后开始一个新的流水线。从功能上讲,这正是你想要的。虽然这不是同一个流水线,但这完全是一种审美上的反对。 - Brian Goetz
3个回答

9
你可以使用 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

7

如果我理解你的问题正确,你需要在使用不等于"b-b"谓词进行过滤之前应用终端操作。然后,在中间结果上调用.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));

这个方向有点对,但我想将中间结果分配给某个变量。也许最好的方法是使用一个带有自己的Collector实现的中间collect - Anton
1
是的,我正要建议您这样做。自定义收集器是您的好帮手。 :) - Konstantin Yovkov

0
如Anton和kocko已经提到的那样,您可以添加自己的收集器,或者使用Stream.collect方法与supplier、accumulator和combiner参数:
    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));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接