Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to define a generic parameter type explicitly in a lambda expression?

I have here a Handler class, which is supposed to handle Events 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 -> { };
like image 818
octopod Avatar asked May 21 '15 01:05

octopod


People also ask

Can lambda expressions be generic?

A lambda expression can't specify type parameters, so it's not generic. However, a functional interface associated with lambda expression is generic.

Is it mandatory to declare type of parameter in lambda expression?

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.

Is parameter types can be inferred in lambda expression?

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.

Can lambda expression contains data type?

The lambda expressions have a very simple, precise syntax and provide flexibility to specify the datatypes for the function parameters.


2 Answers

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

like image 164
sprinter Avatar answered Oct 06 '22 13:10

sprinter


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.

like image 22
newacct Avatar answered Oct 06 '22 12:10

newacct