Passing lambdas to an overloaded method may be ambiguous if two overloads have parameters that are functional interfaces with equivalent methods.
Prefer to avoid ambiguous overloads, and consider renaming one of the methods.
For example Function<String, Integer>
and IntFunction<String>
are both
compatible with the lambda x -> x.hashCode()
.
void f(Function<String, Integer> x) {}
void f(IntFunction<String> x) {}
error: reference to f is ambiguous
f(x -> x.hashCode());
^
both method f(Function<String,Integer>) in Test and method f(IntFunction<String>) in Test match
To avoid the ambiguity, callers will have to use an explicit cast:
f((IntFunction<String>) x -> x.hashCode());
f((Function<String, Integer>) x -> x.hashCode());
The situation is more complicated with expression-bodied lambdas. Consider:
void doIt(Function<String, String> f);
void doIt(Consumer<String> c);
JLS 15.12.2.1 says that lambdas whose body is a statement expression are compatible with functional interfaces whose function type is void-returning or value returning:
A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true:
The arity of the target type’s function type is the same as the arity of the lambda expression.
If the target type’s function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).
If the target type’s function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2).
So, if you have:
doIt(x -> System.gc());
it’s an implicitly typed statement-expression-bodied lambda that’s compatible with both overloads.
Any of the following disambiguate the overloads:
doIt((String x) -> x.toString()); // explicitly typed, calls f(Function)
doIt(x -> (x.toString())); // non-statement expression body, calls f(Function)
doIt(x -> {x.toString();}); // statement body, calls f(Consumer)
Suppress false positives by adding the suppression annotation @SuppressWarnings("FunctionalInterfaceClash")
to the enclosing element.