具有通用抛出子句的 Lambda 和函数接口
考虑以下 java 8 代码片段:
public class Generics {
public static <V, E extends Exception> V f(CheckedCallable1<V, E> callable) throws E {
return callable.call();
}
public static <V, E extends Exception> V g(CheckedCallable2<V, E> callable) throws E {
return callable.call();
}
public static void main(String[] args) {
f(() -> 1);
g(() -> 1);
}
}
interface Callable<V> {
V call() throws Exception;
}
interface CheckedCallable1<V, E extends Exception> {
V call() throws E;
}
interface CheckedCallable2<V, E extends Exception> extends Callable<V> {
@Override V call() throws E;
}
调用编译时的 lambda 正常,而调用时的 lambda 不编译,而是给出以下编译错误:f
g
Error:(10, 7) java: call() in <anonymous Generics$> cannot implement call() in CheckedCallable2
overridden method does not throw java.lang.Exception
这是为什么呢?
在我看来,和 方法都是等价的:根据类型擦除的规则,它变得无界,并成为 ,因为这是类型上限。那么,为什么编译器认为重写的方法不会引发java.lang.Exception呢?CheckedCallable1.call
CheckedCallable2.call
V
Object
E
Exception
即使忽略类型擦除(这在这里可能不相关,因为这一切都发生在编译时),它仍然对我没有意义的:我看不出为什么这种模式如果允许,会导致,比如说,不健全的java代码。
那么有人可以启发我为什么不允许这样做吗?
更新:
所以我发现了一些可能更有趣的东西。获取上述文件,将 每次出现的 to 更改为 ,并将 throws 子句添加到 中。编译作品!改回:编译中断!Exception
IOException
main
Exception
这编译得很好:
import java.io.IOException;
public class Generics {
public static <V, E extends IOException> V f(CheckedCallable1<V, E> callable) throws E {
return callable.call();
}
public static <V, E extends IOException> V g(CheckedCallable2<V, E> callable) throws E {
return callable.call();
}
public static void main(String[] args) throws IOException {
f(() -> 1);
g(() -> 1);
}
}
interface Callable<V> {
V call() throws IOException;
}
interface CheckedCallable1<V, E extends IOException> {
V call() throws E;
}
interface CheckedCallable2<V, E extends IOException> extends Callable<V> {
@Override V call() throws E;
}
在这一点上,它开始看起来越来越像一个java错误......