有没有办法在 lambda 表达式中显式定义泛型参数类型?
Posted
技术标签:
【中文标题】有没有办法在 lambda 表达式中显式定义泛型参数类型?【英文标题】:Is there a way to define a generic parameter type explicitly in a lambda expression? 【发布时间】:2015-08-02 11:57:42 【问题描述】:我这里有一个Handler
类,它应该处理某种类型的Event
s:
public interface Handler<E extends Event>
public void handle(E event);
@SuppressWarnings("unchecked")
public default Class<E> getEventType()
for(Method method: this.getClass().getDeclaredMethods())
if(method.getName().equals("handle")) return (Class<E>)method.getParameterTypes()[0];
throw new NullPointerException("Couldn't find the 'handle' method in this handler.");
如您所见,默认情况下,当您执行 getEventType()
时,它会通过返回 handle()
方法的第一个参数类型(而不是 Handler
显式返回它)。这适用于以下 JUnit 测试:
public static class EmptyEvent extends Event
public void test()
public static Handler<EmptyEvent> genericHandler = new Handler<EmptyEvent>()
@Override
public void handle(EmptyEvent event)
;
@Test
public void testEventGenerics()
//prints the name of EmptyEvent
System.out.println(genericHandler.getEventType());
Intellij IDEA 告诉我可以将 genericHandler
简化为 lambda 表达式,所以我这样做了:
public static class EmptyEvent extends Event
public void test()
public static Handler<EmptyEvent> genericHandler = event -> ;
@Test
public void testEventGenerics()
//prints the name of the base Event class
System.out.println(genericHandler.getEventType());
但是,测试会打印出Event
的名称,而不是EmptyEvent
。
所以我的问题是,有没有办法明确定义 lambda 表达式的泛型参数类型?
我尝试做这样的事情,但它什么也没做(也是一个错误)
public static Handler<EmptyEvent> genericHandler = (EmptyEvent)event -> ;
【问题讨论】:
【参考方案1】:是的,您可以定义 lambda 表达式参数的类型:
public static Handler<EmptyEvent> genericHandler = (EmptyEvent event) -> ;
一般来说没有必要,因为它是由上下文暗示的。然而,它通常使代码更易于阅读。
详情请见https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27
【讨论】:
嗯。它编译并回答了问题,但由于某种原因genericHandler.getEventType()
仍然返回Event
的名称。你知道为什么吗?
@Octopod 可能是因为您依赖于 getDeclaredMethods
返回不同方法的顺序,这是一个禁忌。
@immibis 除了我很确定只有一个 handle()
方法(我定义的那个),不是吗?你是说还有handle(Event)
?
@Octopod 是的;这是一种桥梁方法。我不知道它是否会从getDeclaredMethods返回,但显然它是。
@immibis,我更改了getEventType()
以打印出每个名为handle
的方法。 handle(Event)
是它使用getDeclaredMethods()
找到的唯一方法。 getMethods()
返回相同的东西。【参考方案2】:
您正在对 lambda 评估的对象的类做出假设,我认为这些假设是不成立的。 lambda 覆盖来自Handler
的方法handle()
就足够了,并且在运行时,采用Event
的handle()
方法足以覆盖来自Handler
的handle()
,擦除后采用@987654327 @。无法保证 lambda 必须有一个 handle()
方法,可以自省说它需要 EmptyEvent
。
【讨论】:
【参考方案3】:以下变量可能都指向同一个对象!
Handler<EventA> handlerA = event -> ;
Handler<EventB> handlerB = event -> ;
Consumer<String> consumer1 = string ->
Consumer<Integer> consumer2 = integer->
您无法真正推断出 lambda 表达式的确切运行时类型;唯一的保证是 lambda 主体在运行时工作。
http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.4
[runtime] 方法的主体具有评估 lambda 主体的效果
【讨论】:
以上是关于有没有办法在 lambda 表达式中显式定义泛型参数类型?的主要内容,如果未能解决你的问题,请参考以下文章
是否执行了视图列集中的所有函数,即使它们没有在查询中显式引用?