Java8/Lambdas/Streams:子类化函数<;T、 R>;导致Andhen()方法出现问题
作为更具描述性的界面,我想创建以下内容:Java8/Lambdas/Streams:子类化函数<;T、 R>;导致Andhen()方法出现问题,java,java-8,java-stream,Java,Java 8,Java Stream,作为更具描述性的界面,我想创建以下内容: @FunctionalInterface public interface Dial extends Function<Double,Double> {} //No注释下的代码给出了以下编译错误: 错误:(22,40)java:不兼容的类型:没有类型为的实例 变量V的存在使得 java.util.function.function符合 兰博达斯。表盘 当然//Yes注释下的代码是有效的,但它首先破坏了使用描述性拨号接口的目的 我有几个问题:
@FunctionalInterface
public interface Dial extends Function<Double,Double> {}
//No
注释下的代码给出了以下编译错误:
错误:(22,40)java:不兼容的类型:没有类型为的实例
变量V的存在使得
java.util.function.function符合
兰博达斯。表盘
当然//Yes
注释下的代码是有效的,但它首先破坏了使用描述性拨号接口的目的
我有几个问题:
- Java泛型和lambda的设计/实现带来了什么
这个问题怎么办李>
- 有解决办法吗
- 这是一个很好的实践吗
子类
函数
作为像我这样的描述性接口
或者我应该首先避免这样做
的定义是
default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
默认函数,然后(函数可以找到和的签名。它清楚地表明和返回函数,而不是拨号
Java没有很好的方法为类型创建类型安全别名。从函数
继承的默认
方法被声明为返回函数
,当通过子接口
调用默认
方法时,这一点不会改变。请注意,函数。然后,
允许将<代码>拨号
实例,具有任意的函数
返回不同类型,创建的函数
与您的拨号
的功能签名不兼容:
Function<Double,String> f=dialMult(3.0).andThen(Object::toString);
或者,您可以创建自己的和第二个方法。请注意,此方法不会覆盖函数。第二个(函数)
方法需要限制第二个函数允许的类型参数,这将是一个无效的参数收缩。但用于组合两个拨号实例(或使用unarycoperator
拨号实例)它可以工作
@FunctionalInterface
public interface Dial extends UnaryOperator<Double> {
public default Dial andThen(UnaryOperator<Double> after) {
return d->after.apply(apply(d));
}
}
重写此方法时,可以声明更具体的返回类型,即函数
的子接口,但是,它必须与函数
的类型兼容,这与拨号
不同,因为拨号
扩展了函数
。这需要将参数限制为仅允许Double
用于R
,这是不允许的。要有效替代功能
,子接口本身必须是通用的,才能使用参数化拨号
是功能
,但功能
不一定是拨号
。最好使用双功能YoOperator
,或者至少是UniaryOperator
,而不是函数
。您的拨号
界面基本上是DoubleUniaryOperator
界面的克隆,但没有原语。答案的后半部分(“或者…”)工作非常完美,这正是我想要的。请注意,您还可以对进行简单的协变重写,然后
只优化返回类型并保持参数常量。然后这确实是一个重写,只需使用协变返回类型即可(此功能是在Java5中添加的,同样适用于默认方法。)@Brian Goetz:正如我在回答中所解释的,这正是你不能做的。然后
接受一个具有任意返回类型的任意函数,并且必须返回一个返回类型与第二个函数兼容的函数
。因此,你不能覆盖它来返回一个总是EXT的拨号
实例nds函数
。这需要将函数
的参数限制为函数
,这是不可能的。我对我的答案添加了更详细的解释…如何。如果不修改函数接口,我看不到通过添加一个表示实际派生接口的通用参数来实现这一点的方法。它看起来很难看
Function<Double,String> f=dialMult(3.0).andThen(Object::toString);
Dial d1 = dialMult(3.0).andThen(dialMult(4.0))::apply;
@FunctionalInterface
public interface Dial extends UnaryOperator<Double> {
public default Dial andThen(UnaryOperator<Double> after) {
return d->after.apply(apply(d));
}
}
public interface Dial extends UnaryOperator<Double> {
@Override
public default <R>
Function<Double, R> andThen(Function<? super Double, ? extends R> after) {
return UnaryOperator.super.andThen(after);
}
}