Java:获取lambda的通用类型 [英] Java: Getting the generic type of a lambda

查看:86
本文介绍了Java:获取lambda的通用类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

First, I should say that I am able to get the generic type of instances or anonymous inner classes.

这是代码示例,查找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的引入,我不能再强制执行此操作了!

But with the introduction of Lambdas, i can no longer enforce this!

还应注意,这现在可能会破坏与<之前的库的向后兼容性. 8,并反映出此信息.

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.

注意:我已经看过此主题了: 在Java 8 Lambda上的反射类型推断

推荐答案

您只需编写

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的类型或未经检查的异常,因此很明显,捕获的ex必须是可分配给E的类型或未经检查的异常,因此可以安全地重新执行-抛出.

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.

从Java 7开始有效.

This works since Java 7.

相反,如果您的方法执行其他操作可能会引发不能保证与E兼容的异常,则应显式声明它们,而不要进行反射魔术.否则,您将有一种方法以一种奇怪的方式更改其行为,因为该方法取决于参数,是简单地引发还是以不同的方式处理特定的异常类型(包装或其他后备行为).

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 {
    }
}

直接实例化此类时,您无法在运行时通过反射获取实际的类型参数.这与通过lambda表达式创建的实现完全相同.

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.

这篇关于Java:获取lambda的通用类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆