有没有办法在lambda表达式中显式定义泛型参数类型?

时间:2015-05-21 01:44:12

标签: java generics lambda

我这里有一个Handler类,它应该处理某种类型的Event

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.");
    }
}

正如您所看到的,默认情况下,只要您执行Event,就会尝试通过返回handle()方法的第一个参数类型来获取getEventType()的类型(相反)到显式返回它的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 -> { };

3 个答案:

答案 0 :(得分:4)

是的,您可以定义lambda表达式参数的类型:

public static Handler<EmptyEvent> genericHandler = (EmptyEvent event) -> { };

一般来说,没有必要,因为它是由上下文暗示的。但是,它通常使代码更容易阅读。

有关详细信息,请参阅https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27

答案 1 :(得分:1)

您正在假设lambda评估的对象的类,我不认为这些假设是有效的。 lambda覆盖handle()方法Handler就足够了,在运行时,handle()方法只需Event覆盖handle()即可。 Handler,在删除后Event。无处保证lambda必须有一个handle()方法,可以反过来说它需要EmptyEvent

答案 2 :(得分:0)

以下变量可能都指向同一个对象!

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主体的效果