新的Java 8流框架及其朋友可以编写一些非常简洁的Java代码,但我遇到过一个看似简单的情况,但要做到简洁却很棘手。
考虑一个列表<Thing> things and method Optional<Other> resolve(Thing Thing)。我想映射的东西可选<其他>s,并获得第一个其他。
显而易见的解决方案是使用things.stream().flatMap(this::resolve). findfirst(),但flatMap要求您返回一个流,而Optional没有stream()方法(或者它是一个集合或提供一个方法将其转换为或将其视为一个集合)。
我能想到的最好的是:
things.stream()
.map(this::resolve)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
但对于一个很普通的例子来说,这似乎太啰嗦了。
有人有更好的主意吗?
我想推广用于为函数式api创建helper的工厂方法:
Optional<R> result = things.stream()
.flatMap(streamopt(this::resolve))
.findFirst();
工厂方法:
<T, R> Function<T, Stream<R>> streamopt(Function<T, Optional<R>> f) {
return f.andThen(Optional::stream); // or the J8 alternative:
// return t -> f.apply(t).map(Stream::of).orElseGet(Stream::empty);
}
推理:
与一般的方法引用相比,与lambda表达式相比,你不能意外地从可访问范围中捕获变量,例如:
T -> streamopt(resolve(o))
它是可组合的,你可以调用Function::and然后在工厂方法result上:
streamopt(::解决).andThen(…)
而在lambda的情况下,你需要先强制转换:
((T <函数,流< R > >) T - > streamopt(解决(T))) .andThen(…)