在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
不可链接?
答案 0 :(得分:23)
您正在寻找的方法存在,称为Stream::peek和Stream::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));