I have here a Handler
class, which is supposed to handle Event
s of a certain type:
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.");
}
}
As you can see, it will try, by default, to get the type of Event
by returning the first parameter type of the handle()
method whenever you execute getEventType()
(as opposed to a Handler
that returns it explicitly). This works correctly with the following JUnit test:
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 tells me that I can simplify genericHandler
to a lambda expression, so I do that:
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());
}
however, the test prints out the name of Event
, not EmptyEvent
.
So my question is, Is there a way to explicitly define the generic parameter type of a lambda expression?
I tried doing something like this, but it doesn't do anything (also it's an error)
public static Handler<EmptyEvent> genericHandler = (EmptyEvent)event -> { };
A lambda expression can't specify type parameters, so it's not generic. However, a functional interface associated with lambda expression is generic.
A lambda expression is characterized by the following syntax. Following are the important characteristics of a lambda expression. Optional type declaration − No need to declare the type of a parameter. The compiler can inference the same from the value of the parameter.
A lambda expression can have zero (represented by empty parentheses), one or more parameters. The type of the parameters can be declared explicitly, or it can be inferred from the context. If there is a single parameter, the type is inferred and is not mandatory to use parentheses.
The lambda expressions have a very simple, precise syntax and provide flexibility to specify the datatypes for the function parameters.
Yes you can define the type of a lambda expression parameter:
public static Handler<EmptyEvent> genericHandler = (EmptyEvent event) -> { };
In general it is not necessary because it is implied by context. However it often makes the code easier to read.
See https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27 for more details
You are making assumptions about the class of the object that the lambda evaluates to, and I don't think those assumptions are valid. It is sufficient that the lambda overrides the method handle()
from Handler
, and at runtime, a handle()
method that takes Event
is sufficient to override the handle()
from Handler
, which after erasure takes Event
. Nowhere is it guaranteed that the lambda must have a handle()
method that can be introspected to say that it takes EmptyEvent
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With