OK, so method overloading is-a-bad-thing™. Now that this has been settled, let's assume I actually want to overload a method like this:

static void run(Consumer<Integer> consumer) { System.out.println("consumer"); } static void run(Function<Integer, Integer> function) { System.out.println("function"); }

In Java 7, I could call them easily with non-ambiguous anonymous classes as arguments:

run(new Consumer<Integer>() { public void accept(Integer integer) {} }); run(new Function<Integer, Integer>() { public Integer apply(Integer o) { return 1; } });

Now in Java 8, I'd like to call those methods with lambda expressions of course, and I can!

// Consumer run((Integer i) -> {}); // Function run((Integer i) -> 1);

Since the compiler should be able to infer Integer , why don't I leave Integer away, then?

// Consumer run(i -> {}); // Function run(i -> 1);

But this doesn't compile. The compiler (javac, jdk1.8.0_05) doesn't like that:

Test.java:63: error: reference to run is ambiguous run(i -> {}); ^ both method run(Consumer<Integer>) in Test and method run(Function<Integer,Integer>) in Test match

To me, intuitively, this doesn't make sense. There is absolutely no ambiguity between a lambda expression that yields a return value ("value-compatible") and a lambda expression that yields void ("void-compatible"), as set out in the JLS §15.27.

But of course, the JLS is deep and complex and we inherit 20 years of backwards compatibility history, and there are new things like:

Certain argument expressions that contain implicitly typed lambda expressions (§15.27.1) or inexact method references (§15.13.1) are ignored by the applicability tests, because their meaning cannot be determined until a target type is selected. from JLS §15.12.2

The above limitation is probably related to the fact that JEP 101 wasn't implemented all the way, as can be seen here and here.

Question:

Who can tell me exactly what parts of the JLS specifies this compile-time ambiguity (or is it a compiler bug)?

Bonus: Why were things decided this way?

Update:

With jdk1.8.0_40, the above compiles and works fine