I have an overloaded method that takes two different functional interfaces as parameters (Runnble
and Supplier
). System.out.println
is clearly only compatible with Runnable
, because it is a void
method. Yet the compiler still claims that the call is ambiguous. How is that possible?
import java.util.function.Supplier;
public class GenericLambdas {
public static void main(String[] args) {
wrap(System.out::println); // Compiler error here
wrap(() -> {}); // No error
wrap(System.out::flush); // No error
}
static <R> void wrap(Supplier<R> function) {}
static void wrap(Runnable function) {}
}
Compiler output:
Error:Error:line (5)java: reference to wrap is ambiguous
both method <R>wrap(java.util.function.Supplier<R>) in GenericLambdas and method wrap(java.lang.Runnable) in GenericLambdas match
Error:Error:line (5)java: incompatible types: cannot infer type-variable(s) R
(argument mismatch; bad return type in method reference
void cannot be converted to R)
Based on the second error (argument mismatch, void cannot be converted to R
), shouldn't the compiler be able to disambiguate the call? That would then take care of both compiler errors (as it will neither be ambiguous, nor will it try to convert void to R).
And why are () -> {}
and System.out::flush
able to resolve? They have the same signature as System.out.println
. Granted that System.out.println
is overloaded with versions that take an argument, but none of those overloaded versions match either Supplier
or Runnable
, so I don't see how they would be relevant here.
EDIT:
It seems that this does compile and run with the Eclipse compiler. Which compiler is correct, or is either behavior allowed?