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

wen*_*ner 9 java java-8

在java 8中,java.util.stream.Stream#forEach考虑作为传统for循环的替代.但为什么不是这不是链函数.它返回虚空而不是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);
Run Code Online (Sandbox Code Playgroud)

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

那么,为什么forEach不能连锁?

nos*_*sid 25

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

Arrays
    .stream(Girls.toArray())
    .peek(Girls::getUp)
    .peek(Girls::dressUp)
    .filter(/* Top 10 Girls */)
    .peek(Gay.getMe()::gotGirl)
    ...
Run Code Online (Sandbox Code Playgroud)

  • 但是,请注意,在`peek()`或`map()`中可能会干扰源的行为参数或影响其他流操作的结果的副作用是禁止的.`peek()`方法实际上只用于调试/记录,而不是用于计算结果; 类似地,`map()`应仅用于转换,而不是用于隐藏副作用. (12认同)

JB *_*zet 12

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

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


Stu*_*rks 7

forEach操作确实是终端操作,因此不可链接,但是可以将多个操作(在这种情况下为消费者)组成单个forEach调用.例如:

    Consumer<String> c1 = s -> System.out.println(s + "1");
    Consumer<String> c2 = s -> System.out.println(s + "2");
    Consumer<String> c3 = s -> System.out.println(s + "3");
    Arrays.asList("a", "b", "c")
          .stream()
          .forEach(c1.andThen(c2).andThen(c3));
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果没有一堆丑陋的演员,看起来不可能将lambdas写成内联.


小智 5

继续Stuart Marks 的回答,可以内联编写 lambda,但只有第一个消费者需要强制转换:

Arrays.asList("a", "b", "c").forEach(
    ((Consumer<String>) s -> System.out.println(s + "1"))
    .andThen(s->System.out.println(s + "2"))
    .andThen(s -> System.out.println(s + "3"))
);
Run Code Online (Sandbox Code Playgroud)

  • 每次你进行明确的演员表演时,就会有一个仙女死去。 (4认同)