Java:获取lambda的泛型类型

时间:2014-12-18 15:40:11

标签: java java-8

首先,我应该说我能够获得泛型类型的实例或匿名内部类。

以下是代码示例,查找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

1 个答案:

答案 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表达式创建的实现完全相同。