Search code examples
javalambda

Java lambda argument type not inferred correctly


I'm trying to call this method on javafx: TableColumn.setOnEditCommit. This method's definition is the following:

public final void setOnEditCommit(EventHandler<CellEditEvent<S,T>> value) {
    // ...
}

As you can see, it explicitely requires an EventHandler of type CellEditEvent (which extends Event). The EventHandler's definition:

public interface EventHandler<T extends Event> extends EventListener {
    void handle(T event);
}

Obvious enough, to call setOnEditCommit (without lamba), one would type this:

column.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent>() {
    public void handle(CellEditEvent event) {
        event.getTableView().doSomething();
    }
});

Note: getTableView is a method of CellEditEvent, but not of Event.

All nice so far. The problem I've come into is that writing the above code seems to be impossible using lambda, without casting. That is, the lamba equivalent for the above is:

column.setOnEditCommit(event -> event.getTableView().doSomething());

Here's the problem. Lambda doesn't care that the event should be a CellEditEvent because the setOnEditCommit method explicitely states the EventHandler's vararg is a CellEditEvent.

Apparently, when inferring argument types, lambda checks out the EventHandler class definition, in particular the <T extends Event> part, and then decides that T is an Event, and that's it, not that t extends Event. In this case, the error thrown is that method 'getTableView' is not found - because the Event class doesn't have that method.

Not only that, but not even explicitely stating the argument type doesn't work:

column.setOnEditCommit((TableColumn.CellEditEvent event) -> event.getTableView().doSomething());

Results in the error:

Error:(10, 32) java: incompatible types: incompatible parameter types in lambda expression

My question is: Why doesn't lambda correctly infer that the argument should be T extends Event (CellEditEvent in this case), not Event, and is there any way to fix that?

Full example:

import javafx.scene.control.TableColumn;
public class Main {
    public static void main(String[] args) {
        TableColumn column = null;
        column.setOnEditCommit(event -> event.getTableView());
    }
}

Solution

  • Apparently using raw types for the TableColumn causes this issue to happen. So this will work:

    TableColumn<SomeClass, SomeOtherClass> column = null;
    column.setOnEditCommit(event -> event.getTableView());
    

    Not only that, but also this:

    TableColumn<?, ?> column = null;
    column.setOnEditCommit(event -> event.getTableView());
    

    But this will not:

    TableColumn column = null;
    column.setOnEditCommit(event -> event.getTableView());