问题
First, I should say that I am able to get the generic type of instances or anonymous inner classes.
Here is the code example, look for the catch block:
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();
}
This doesn't work:
method(() -> {
throwsException();
});
But this does:
method(new MyInterface<Exception>() {
@Override
public void call() throws Exception {
throwsException();
}
});
But with the introduction of Lambdas, i can no longer enforce this!
It should also be noted that this now potentially breaks backwards compatibility with Libraries older than < 8, and that reflected out this information.
I have researched this topic, and there only seems to be possible workarounds for getting the method parameters, but this is regarding the throws part so that won't work.
Note: I have seen this thread already: Reflection type inference on Java 8 Lambdas
回答1:
You can simply write
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;
}
}
without dealing with Reflection. Since MyInterface<E>.call()
is guaranteed to throw types assignable to E
or unchecked exceptions only, it is clear that the catched ex
must be either of a type assignable to E
or an unchecked exception, hence may be safely re-thrown.
This works since Java 7.
In contrast, if your method performs other operations which may throw exceptions not guaranteed to be compatible with E
, you should declare them explicitly rather than doing Reflection magic. Otherwise you have a method changing its behavior in a strange way as it depends then on the parameter whether a particular exception type is simply thrown or handled differently (wrapped or whatever your fall-back behavior is).
Note that your Reflection magic is broken anyway. Consider this simple example:
class Foo<E extends Throwable> implements MyInterface<E> {
public void call() throws E {
}
}
when instantiating this class directly, you can’t get the actual type arguments at runtime via Reflection. This is exactly the same behavior as with implementations created via lambda expressions.
来源:https://stackoverflow.com/questions/27550314/java-getting-the-generic-type-of-a-lambda