首先,我应该说我能够获得泛型类型的实例或匿名内部类。
以下是代码示例,查找catch块:
public static interface MyInterface<E extends Throwable>{
void call() throws E;
}
public static <E extends Throwable> void method(MyInterface<E> lambda) throws E {
try {
lambda.call();
} catch(Throwable ex) {
// Pseudo code
Class<?> T = ((ParameterizedType)ex.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
if ( T.isInstance(ex) ) {
throw ex;
} else {
...
}
}
}
public static void throwsException() throws Exception {
throw new Exception();
}
这不起作用:
method(() -> {
throwsException();
});
但这样做:
method(new MyInterface<Exception>() {
@Override
public void call() throws Exception {
throwsException();
}
});
但随着Lambdas的推出,我再也不能强制执行了!
还应该注意,这现在可能会破坏与早于&lt;的文库的向后兼容性。 8,并反映出这些信息。
我已经研究了这个主题,并且似乎只有可能的方法来获取方法参数,但这是关于throws部分,以便不会工作。
注意:我已经看过这个帖子了: Reflection type inference on Java 8 Lambdas
答案 0 :(得分:4)
你可以简单地写
public static interface MyInterface<E extends Throwable>{
void call() throws E;
}
public static <E extends Throwable> void method(MyInterface<E> lambda) throws E {
try {
lambda.call();
}
catch(Throwable ex) {
throw ex;
}
}
没有处理反射。由于MyInterface<E>.call()
可以保证将类型分配给E
或仅仅是未经检查的例外,因此很明显,cat ex
必须是可分配给E
的类型或未选中的类型异常,因此可以安全地重新抛出。
这是自Java 7以来的。
相反,如果你的方法执行其他操作可能会抛出异常并不能保证与E
兼容,那么你应该明确地声明它们而不是做反射魔法。否则你有一个方法以一种奇怪的方式改变它的行为,因为它依赖于参数是否只是抛出或处理不同的特定异常类型(包装或任何你的后退行为)。
请注意,无论如何你的反射魔法都会被打破。考虑这个简单的例子:
class Foo<E extends Throwable> implements MyInterface<E> {
public void call() throws E {
}
}
直接实例化此类时,无法通过Reflection在运行时获取实际的类型参数。这与通过lambda表达式创建的实现完全相同。