使用时出现的问题compose
or andThen
是它们内置于Function
它们返回的函数的接口和类型(编译时类型和运行时类型)是Function
并不是UnaryOperator
或您定义的子接口。例如,假设我们有
UnaryOperator<String> a = s -> s + "bar";
UnaryOperator<String> b = s -> s + s;
有人可能认为我们可以写
UnaryOperator<String> c = a.compose(b);
但这行不通!相反,人们必须写
Function<String, String> c = a.compose(b);
为了做到这一点,UnaryOperator
必须提供协变覆盖andThen
and 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"));
}
这打印出来[foobar][foobar]
。请注意,我使用了两个参数形式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));
}
}
这将按如下方式使用:
MyOperator composite =
list.stream()
.reduce(MyOperator.identity(), (a, b) -> a.andThen(b));
是否增大接口以便写入andThen
我想,而不是嵌套的 lambda 是一个品味问题。