lambda 与匿名 class
lambda vs 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 表达式替换这两个匿名 classes,例如:
eventBus.subscribe((EventBusListener<NavigationEvent>) Event::getPayload);
eventBus.subscribe((EventBusListener<NotificationEvent>) Event::getPayload);
编译工作正常,但在运行时应用程序崩溃并出现以下错误:java.lang.IllegalArgumentException: Could not resolve payload type
由 Event<T>
class 的 getPayload()
引起。
lamdbas
和 generics
我错过了什么?
你的方法引用没有问题,但是 IllegalArgumentException
也没有被那个子系统抛出。
问题似乎与 eventBus.subscribe
内部所做的有关。由于类型擦除,只有一个subscribe(EventBusListener)
方法,不知道你传入的是EventBusListener<NavigationEvent>
还是EventBusListener<NotificationEvent>
。
正如消息“无法解析有效载荷类型”所指示的,它无论如何都会尝试找出实际的有效载荷类型,这意味着使用反射。这仅适用于 reifiable,即非通用类型。你的匿名内部 classes 是 reifiable 类型,它们本身不是通用的,但有一个通用的超级 class/interface 可以通过 getGenericSuperclass()
resp. getGenericInterfaces()
.
在该上下文中使用方法引用或 lambda 表达式的问题在于,如果接口是通用的,则生成的运行时 class 将不会 可具体化 ,也就是说,您无法通过反射找出实际的类型参数。就像你写了
eventBus.subscribe(Event::getPayload);
除非有一个重载方法允许您显式指定负载类型,否则这不适用于 lambda 表达式或方法引用。
取决于框架如何在内部解析类型,使用 reifiable 接口可能会起作用,例如
interface NavigationEventListener extends EventBusListener<NavigationEvent> {}
…
eventBus.subscribe((NavigationEventListener)Event::getPayload);
当然,只有在您要实例化多个此类侦听器时,这才会有回报,否则,您可以继续使用匿名内部 class(除非他们捕获 this
实例是你的问题)。
我有以下代码:
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 表达式替换这两个匿名 classes,例如:
eventBus.subscribe((EventBusListener<NavigationEvent>) Event::getPayload);
eventBus.subscribe((EventBusListener<NotificationEvent>) Event::getPayload);
编译工作正常,但在运行时应用程序崩溃并出现以下错误:java.lang.IllegalArgumentException: Could not resolve payload type
由 Event<T>
class 的 getPayload()
引起。
lamdbas
和 generics
我错过了什么?
你的方法引用没有问题,但是 IllegalArgumentException
也没有被那个子系统抛出。
问题似乎与 eventBus.subscribe
内部所做的有关。由于类型擦除,只有一个subscribe(EventBusListener)
方法,不知道你传入的是EventBusListener<NavigationEvent>
还是EventBusListener<NotificationEvent>
。
正如消息“无法解析有效载荷类型”所指示的,它无论如何都会尝试找出实际的有效载荷类型,这意味着使用反射。这仅适用于 reifiable,即非通用类型。你的匿名内部 classes 是 reifiable 类型,它们本身不是通用的,但有一个通用的超级 class/interface 可以通过 getGenericSuperclass()
resp. getGenericInterfaces()
.
在该上下文中使用方法引用或 lambda 表达式的问题在于,如果接口是通用的,则生成的运行时 class 将不会 可具体化 ,也就是说,您无法通过反射找出实际的类型参数。就像你写了
eventBus.subscribe(Event::getPayload);
除非有一个重载方法允许您显式指定负载类型,否则这不适用于 lambda 表达式或方法引用。
取决于框架如何在内部解析类型,使用 reifiable 接口可能会起作用,例如
interface NavigationEventListener extends EventBusListener<NavigationEvent> {}
…
eventBus.subscribe((NavigationEventListener)Event::getPayload);
当然,只有在您要实例化多个此类侦听器时,这才会有回报,否则,您可以继续使用匿名内部 class(除非他们捕获 this
实例是你的问题)。