Search code examples
javajava-8compiler-errorsjava-streamfunctional-interface

Java compilation error creating a reversed comparator


Here is a code snippet which is throwing an weird compilation error in Java 8 at line number 2.

List<Employee> employees = getEmployees();
/*Line no:2*/  Comparator<String> comparator = ((emp1, emp2) -> emp1.compareTo(emp2)).reversed();
return employees.stream().map(emp -> emp.getName()).sorted(comparator)
                .collect(Collectors.toList());

The error given is "The target type of this expression must be a functional interface".

The following nearly identical code compile and runs correctly at line number 3

List<Employee> employees = getEmployees();
Comparator<String> comparator = ((emp1, emp2) -> emp1.compareTo(emp2));
/* Line no:3 */  comparator = comparator.reversed(); // NO ERROR GENERATED
return employees.stream().map(emp -> emp.getName()).sorted(comparator)
                .collect(Collectors.toList());

Can some one explain to me what's happening behind the scenes and why this error occurs?


Solution

  • A lambda is just a more concise way to generate an implementation of a functional interface. It can only be used where it's clear what type the lambda should be conforming to. In the context of the expression ((emp1, emp2) -> emp1.compareTo(emp2)).reversed(), the lambda is not immediately being assigned to a variable or being passed to a function (which would allow its type to be inferred), but is a subexpression of a larger expression. This causes the issue.

    You can make the type explicit by casting:

    var comparator = ((Comparator<String>)(emp1, emp2) -> emp1.compareTo(emp2)).reversed();
    

    From the Java tutorial:

    To determine the type of a lambda expression, the Java compiler uses the target type of the context or situation in which the lambda expression was found. It follows that you can only use lambda expressions in situations in which the Java compiler can determine a target type:
    • Variable declarations
    • Assignments
    • Return statements
    • Array initializers
    • Method or constructor arguments
    • Lambda expression bodies
    • Conditional expressions, ?:
    • Cast expressions