lambda vs匿名类

时间:2017-05-16 15:15:36

标签: generics lambda java-8 anonymous-class

我有以下代码:

eventBus.subscribe(new EventBusListener<NavigationEvent>() {
    @Override
    public void onEvent(Event<NavigationEvent> event) {
        event.getPayload();
    }
});

eventBus.subscribe(new EventBusListener<NotificationEvent>() {
    @Override
    public void onEvent(Event<NotificationEvent> event) {
        event.getPayload();
    }
});

IntelliJ告诉我,我可以用lambda表达式替换这两个匿名类,比如:

eventBus.subscribe((EventBusListener<NavigationEvent>) Event::getPayload);
eventBus.subscribe((EventBusListener<NotificationEvent>) Event::getPayload);

编译工作正常,但在运行时,应用程序崩溃时出现以下错误:java.lang.IllegalArgumentException: Could not resolve payload typegetPayload()类引起Event<T>

lamdbasgenerics错过了什么?

1 个答案:

答案 0 :(得分:7)

您的方法引用没有任何问题,但该子系统也没有抛出IllegalArgumentException

似乎问题与内部eventBus.subscribe的作用有关。由于类型擦除,只有一种subscribe(EventBusListener)方法,不知道您是否通过了EventBusListener<NavigationEvent>EventBusListener<NotificationEvent>

由于消息“无法解析有效负载类型”表示,它会尝试找出实际的有效负载类型,这意味着使用反射。这仅适用于可恢复,即非通用类型。您的匿名内部类是可恢复的类型,不是通用的,而是具有可以通过getGenericSuperclass() resp检查的通用超类/接口。 getGenericInterfaces()

在该上下文中使用方法引用或lambda表达式的问题是,如果接口是通用的,则生成的运行时类将不会可再现,即您无法找到实际的通过Reflection输入类型参数。这就像你干草写的那样

eventBus.subscribe(Event::getPayload);

除非有重载方法允许您明确指定有效负载类型,否则这不适用于lambda表达式或方法引用。

取决于框架如何在内部解析类型,使用可重新生成的接口可能有效,例如

interface NavigationEventListener extends EventBusListener<NavigationEvent> {}
…

eventBus.subscribe((NavigationEventListener)Event::getPayload);

当然,如果您要实例化多个类型的侦听器,这只会得到回报,否则,您可以继续使用匿名内部类(除非他们捕获this实例是您的问题)。