为什么不链接java.util.stream.Stream#forEach

时间:2014-06-14 10:41:48

标签: java java-8

在java 8中,java.util.stream.Stream#forEach被认为是传统for循环的替代品。但是为什么这不是链函数。它返回void而不是Stream<T>它自己。

喜欢这个

Arrays
    .stream(Girls.toArray())
    .forEach(Girls::getUp)
    .forEach(Girls::dressUp)
    .filter(/* Top 10 Girls */)
    .forEach(Gay.getMe()::gotGirl)
    .endFilter()// Not an API, but it means remove last filter
    .filter(/* Worst 10 Girls */)
    .forEach(Gay.get(0)::gotGirl)


girls = Arrays
    .stream(Girls.toArray());
girls.forEach(g->{g.getUp();g.dressUp()});
girls.filter(/* Top 10 Girls */)
    .forEach(Gay.getMe()::gotGirl);
girls.filter(/* Worst 10 Girls */)
    .forEach(Gay.get(0)::gotGirl);

第一个比第二个好。但是第一个表现更差。

那么,为什么forEach不可链接?

6 个答案:

答案 0 :(得分:23)

您正在寻找的方法存在,称为Stream::peekStream::map。使用Stream::peek,上面的代码可能如下所示。

Arrays
    .stream(Girls.toArray())
    .peek(Girls::getUp)
    .peek(Girls::dressUp)
    .filter(/* Top 10 Girls */)
    .peek(Gay.getMe()::gotGirl)
    ...

答案 1 :(得分:12)

因为forEach是终端操作。它强制流消耗其所有元素并为每个元素调用消费者。完成后,流已被消耗,无法重复使用。

Stream可以根据需要进行多次中间操作,但只能进行一次终端操作。

答案 2 :(得分:6)

forEach操作确实是终端操作,因此不可链接,但可以将多个操作(在本例中为使用者)组成一个{{1}打电话。例如:

forEach

不幸的是,如果没有一堆丑陋的演员,似乎不可能将lambdas写成内联。

答案 3 :(得分:3)

继续Stuart Marks' answer,可以内联编写lambdas,但只需要第一个消费者投射:

192.168.1.1

答案 4 :(得分:2)

andThen进行链接确实是可行的方法,但我们需要一些语法糖才能让它变得漂亮:

public class Consumers {
    public static <T> Consumer<T> of(Consumer<T> base) {
        return base;
    }
}

这允许我们这样做:

Arrays.asList("a", "b", "c")
      .stream()
      .forEach(Consumers.of(s -> System.out.println(s + "1"))
                        .andThen(s -> System.out.println(s + "2"))
                        .andThen(s -> System.out.println(s + "3")));

或(更短):

Arrays.asList("a", "b", "c")
      .forEach(Consumers.of(s -> System.out.println(s + "1"))
                        .andThen(s -> System.out.println(s + "2"))
                        .andThen(s -> System.out.println(s + "3")));

(因为forEach可直接在集合中使用)

答案 5 :(得分:0)

由于andThen在Java 8中定义为

default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}

您可以轻松为任意数量的功能创建自己的复合Consumer<T>

class CompositeConsumer<T> implements Consumer<T> {
    private final List<Consumer<T>> funcs;

    CompositeConsumer(List<Consumer<T>> funcs) {
        this.funcs = funcs;
    }

    @Override
    public void accept(T t) {
        for (Consumer<T> func: funcs) {
            func.accept(t); 
        } 
    }
}

并立即将其用于任意数量的功能

List<Consumer<String>> funcs = ...
Arrays.asList("a", "b", "c")
      .forEach(new CompositeConsumer(funcs));