ABT*_*ABT 8 java functional-programming java-8
在Java 8中减少UnaryOperator列表的首选方法是什么,直到它们代表一个我可以调用的UnaryOperator应用?例如,我有以下内容
interface MyFilter extends UnaryOperator<MyObject>{};
public MyObject filterIt(List<MyFilter> filters,MyObject obj){
Optional<MyFilter> mf = filters
.stream()
.reduce( (f1,f2)->(MyFilter)f1.andThen(f2));
return mf.map(f->f.apply(obj)).orElse(obj);
}
Run Code Online (Sandbox Code Playgroud)
但是这个代码将引发ClassCastException的(MyFilter)f1.andThen(f2).我真的想要这个代码的效果到底:
MyObject o = obj;
for(MyFilter f:filters){
o = f.apply(o);
}
return o;
Run Code Online (Sandbox Code Playgroud)
但我也很好奇我们如何使用compose或者将函数集合减少到一个函数andThen.
Stu*_*rks 12
使用的问题compose或andThen是,他们建立在Function接口和类型-编译时和运行时类型-他们返回的功能是Function不UnaryOperator或子接口,如您已经定义.例如,假设我们有
UnaryOperator<String> a = s -> s + "bar";
UnaryOperator<String> b = s -> s + s;
Run Code Online (Sandbox Code Playgroud)
有人可能会认为我们可以写
UnaryOperator<String> c = a.compose(b);
Run Code Online (Sandbox Code Playgroud)
但这不起作用!相反,一个人必须写
Function<String, String> c = a.compose(b);
Run Code Online (Sandbox Code Playgroud)
对于这项工作,UnaryOperator必须提供的协变覆盖andThen和compose.(可以说这是API中的一个错误.)您在子接口中也会这样做.或者,用手写出lambda是很简单的.例如,
interface MyOperator extends UnaryOperator<String> { }
public static void main(String[] args) {
List<MyOperator> list =
Arrays.asList(s -> s + "bar",
s -> "[" + s + "]",
s -> s + s);
MyOperator composite =
list.stream()
.reduce(s -> s, (a, b) -> s -> b.apply(a.apply(s)));
System.out.println(composite.apply("foo"));
}
Run Code Online (Sandbox Code Playgroud)
打印出来[foobar][foobar].请注意,我使用了两个arg形式,reduce以避免不得不处理Optional.
或者,如果您正在进行很多功能组合,则可以在自己的界面中重新实现所需的方法.这不是太难.这些是基于实现的,java.util.Function但是String我在本例中使用的具体类型替代了泛型.
interface MyOperator extends UnaryOperator<String> {
static MyOperator identity() {
return s -> s;
}
default MyOperator andThen(MyOperator after) {
Objects.requireNonNull(after);
return s -> after.apply(this.apply(s));
}
default MyOperator compose(MyOperator before) {
Objects.requireNonNull(before);
return s -> this.apply(before.apply(s));
}
}
Run Code Online (Sandbox Code Playgroud)
这将使用如下:
MyOperator composite =
list.stream()
.reduce(MyOperator.identity(), (a, b) -> a.andThen(b));
Run Code Online (Sandbox Code Playgroud)
andThen我猜,是否填充界面以便编写而不是嵌套的lambda是一个品味问题.
MyFilter继承该方法andThen从Function因此返回的类型是Function,不能转换为MyFilter。但由于它具有所需的函数签名,您可以MyFilter使用 lambda 或方法引用创建实例。
例如更改(f1,f2)->(MyFilter)f1.andThen(f2)为(f1,f2)-> f1.andThen(f2)::apply.
通过此更改,整个方法如下所示:
public static MyObject filterIt(List<MyFilter> filters, MyObject obj) {
Optional<MyFilter> mf =
filters.stream().reduce( (f1,f2)-> f1.andThen(f2)::apply);
return mf.map(f->f.apply(obj)).orElse(obj);
}
Run Code Online (Sandbox Code Playgroud)
但是你应该重新考虑你的设计。没有必要让结果函数成为 的实例MyFilter,事实上,甚至输入也可以放宽到接受不仅仅是List<MyFilter>:
// will accept List<MyFilter> as input
public static MyObject filterIt(
List<? extends Function<MyObject,MyObject>> filters, MyObject obj) {
List<Function<MyObject,MyObject>> l=Collections.unmodifiableList(filters);
Optional<Function<MyObject,MyObject>> mf=l.stream().reduce(Function::andThen);
return mf.orElse(Function.identity()).apply(obj);
}
Run Code Online (Sandbox Code Playgroud)
或者,使用 Stuart Marks 的提示来摆脱Optional:
// will accept List<MyFilter> as input
public static MyObject filterIt(
List<? extends Function<MyObject,MyObject>> filters,MyObject obj) {
List<Function<MyObject,MyObject>> l=Collections.unmodifiableList(filters);
return l.stream().reduce(Function.identity(), Function::andThen).apply(obj);
}
Run Code Online (Sandbox Code Playgroud)
只是为了完整性,或者您可以将MyFilters 链接到流上,而不是编写新函数:
public static MyObject filterIt2(List<MyFilter> filters,MyObject obj) {
Stream<MyObject> s=Stream.of(obj);
for(MyFilter f: filters) s=s.map(f);
return s.findAny().get();
}
Run Code Online (Sandbox Code Playgroud)
通过在其抽象方法上使用方法引用语法,可以将功能接口转换为另一个功能接口。
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
public class Example {
public static void main(String[] args) {
Stream<UnaryOperator<String>> stringMappers = Stream.of(
s -> s + "bar",
s -> "[" + s + "]",
s -> s + s
);
UnaryOperator<String> f = stringMappers.reduce(
s -> s,
(a, b) -> a.andThen(b)::apply
);
System.out.println(f.apply("foo"));
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2621 次 |
| 最近记录: |