Consider the following test:
import java.util.AbstractList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.function.BiFunction; import java.util.function.Function; public final class Example { static class PairList<A, B> { public void replaceAllSecond(Function<? super B, ? extends B> secondFunction) {} public void replaceAllSecond(BiFunction<? super A, ? super B, ? extends B> secondFunction) {} } static class ImmutableList<E> extends AbstractList<E> { public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) {return null;} public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {return null;} public static <E> ImmutableList<E> copyOf(Iterator<? extends E> elements) {return null;} public static <E> ImmutableList<E> copyOf(E[] elements) {return null;} @Override public E get(int index) {return null;} @Override public int size() {return 0;} } public static void foo() { PairList<Integer, List<Integer>> list = new PairList<>(); list.replaceAllSecond(x -> ImmutableList.copyOf(x));
Compiling with javac from Oracle JDK 8u40, a replaceAllSecond call with a lambda is accepted, but a call passing a method reference is rejected with the following error:
Example.java:26: error: reference to replaceAllSecond is ambiguous list.replaceAllSecond(ImmutableList::copyOf); //error ^ both method replaceAllSecond(Function<? super B,? extends B>) in PairList and method replaceAllSecond(BiFunction<? super A,? super B,? extends B>) in PairList match where B,A are type-variables: B extends Object declared in class PairList A extends Object declared in class PairList 1 error
I don't understand why using BiFunction overload BiFunction potentially applicable here. From JLS 15.12.2.1 (with some bullets down):
A member method is potentially applicable to a method call if and only if the following is true:
- If the element is a fixed arity method with arity n, the arity of the method call is n, and for all I (1 ≤ i ≤ n) the i-th argument of the method call is potentially compatible, as defined below, with the type of the i-th parameter of the method.
The expression is potentially compatible with the target type according to the following rules:
A method reference expression (§15.13) is potentially compatible with a functional interface type if, when the type type of the arty type is n, there is at least one potentially applicable method for the method reference expression with arity n (§15.13.1), and one of the following right:
- The method reference expression is of the form ReferenceType :: [TypeArguments] An identifier and at least one potentially applicable method: i) static and supports arity n, or ii) non-static and supports arity n-1.
As I understand it, the BiFunction type of the arity function is 2, but all copyOf overloads are static and have arity 1, so the method reference is not potentially compatible with the BiFunction parameter and therefore replaceAllSecond(BiFunction) not potentially applicable.
Am I misinterpreting JLS, or is it a javac error? JDK-8026231 describes a javac update to implement the specification, but this error was resolved in 2013, before the first version of Java 8 (in March 2014).
java java-8 jls method-reference
Jeffrey bosboom
source share