lambda vs匿名类

lou*_*ros 6 generics lambda anonymous-class java-8

我有以下代码:

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();
    }
});
Run Code Online (Sandbox Code Playgroud)

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

eventBus.subscribe((EventBusListener<NavigationEvent>) Event::getPayload);
eventBus.subscribe((EventBusListener<NotificationEvent>) Event::getPayload);
Run Code Online (Sandbox Code Playgroud)

编译效果很好,但在运行时,出现以下错误的应用程序崩溃:java.lang.IllegalArgumentException: Could not resolve payload type引起getPayload()Event<T>类.

我是缺少什么lamdbasgenerics

Hol*_*ger 7

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

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

正如消息"无法解析有效负载类型"所示,它会尝试找出实际的有效负载类型,这意味着使用反射.这仅适用于可回收的,即非通用类型.你的匿名内部类是可复制的类型,不是通用的,而是具有可以通过getGenericSuperclass()resp 检查的通用超类/接口.getGenericInterfaces().

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

eventBus.subscribe(Event::getPayload);
Run Code Online (Sandbox Code Playgroud)

除非存在允许您明确指定有效内容类型的重载方法,否则这将不适用于lambda表达式或方法引用.

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

interface NavigationEventListener extends EventBusListener<NavigationEvent> {}
…

eventBus.subscribe((NavigationEventListener)Event::getPayload);
Run Code Online (Sandbox Code Playgroud)

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