我有以下代码:
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:无法解析由事件< T>的getPayload()引起的有效内容类型类.
lamdbas和generics我缺少什么?
解决方法
您的方法引用没有任何问题,但该子系统也没有抛出IllegalArgumentException.
似乎问题与eventBus.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);
当然,如果您要实例化多个类型的监听器,这只会得到回报,否则,您可以继续使用匿名内部类(除非他们捕获此实例是您的问题).