Java: Getting the generic type of a lambda

最后都变了- 提交于 2021-02-07 08:37:03

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!