java - Reference to method is ambiguous when using lambdas and generics -
i getting error on following code, believe should not there... using jdk 8u40 compile code.
public class ambiguous { public static void main(string[] args) { consumerintfunctiontest(data -> { arrays.sort(data); }, int[]::new); consumerintfunctiontest(arrays::sort, int[]::new); } private static <t> void consumerintfunctiontest(final consumer<t> consumer, final intfunction<t> generator) { } private static <t> void consumerintfunctiontest(final function<t, ?> consumer, final intfunction<t> generator) { } }
the error following:
error:(17, 9) java: reference consumerintfunctiontest ambiguous both method consumerintfunctiontest(java.util.function.consumer,java.util.function.intfunction) in net.tuis.ubench.ambiguous , method consumerintfunctiontest(java.util.function.function,java.util.function.intfunction) in net.tuis.ubench.ambiguous match
the error occurs on following line:
consumerintfunctiontest(arrays::sort, int[]::new);
i believe there should no error, arrays::sort
references of type void
, , none of them return value. can observe, does work when explicitly expand consumer<t>
lambda.
is bug in javac, or jls state lambda cannot automatically expanded in case? if latter, still think weird, consumerintfunctiontest
first argument function<t, ?>
should not match.
in first example
consumerintfunctiontest(data -> { arrays.sort(data); }, int[]::new);
the lambda expression has void
-compatible block can identified structure of expression without need resolve actual types.
in contrast, in example
consumerintfunctiontest(arrays::sort, int[]::new);
the method reference has resolved find out, whether conforms either, void
function (consumer
) or value returning function (function
). same applies simplified lambda expression
consumerintfunctiontest(data -> arrays.sort(data), int[]::new);
which both, void
- compatible or value- compatible, depending on resolved target method.
the problem resolving method requires knowledge required signature, ought determined via target typing, target type isn’t known until type parameters of generic method known. while in theory both determined @ once, (still being awfully complex) process has been simplified in specification in method overload resolution performed first , type inference applied last (see jls §15.12.2). hence, information type inference provide cannot used solving overload resolution.
but note first step described in 15.12.2.1. identify potentially applicable methods contains:
an expression potentially compatible target type according following rules:
a lambda expression (§15.27) potentially compatible functional interface type (§9.8) if of following true:
the arity of target type's function type same arity of lambda expression.
if target type's function type has void return, lambda body either statement expression (§14.8) or void-compatible block (§15.27.2).
if target type's function type has (non-void) return type, lambda body either expression or value-compatible block (§15.27.2).
a method reference expression (§15.13) potentially compatible functional interface type if, type's function type arity n, there exists @ least 1 potentially applicable method method reference expression arity n (§15.13.1), , 1 of following true:
the method reference expression has form referencetype :: [typearguments] identifier , @ least 1 potentially applicable method i) static , supports arity n, or ii) not static , supports arity n-1.
the method reference expression has other form , @ least 1 potentially applicable method not static.
…
the definition of potential applicability goes beyond basic arity check take account presence , "shape" of functional interface target types. in cases involving type argument inference, lambda expression appearing method invocation argument cannot typed until after overload resolution.
so in first example 1 of methods sorted out lambda’s shape while in case of method reference or lambda expression consisting of sole invocation expression, both potentially applicable methods endure first selection process , yield “ambiguous” error before type inference can kick in aid finding target method determine if it’s void
or value returning method.
note using x->{ foo(); }
make lambda expression explicitly void
-compatible, can use x->( foo() )
make lambda expression explicitly value-compatible.
you mad further read this answer explaining limitation of combined type inference , method overload resolution deliberate (but not easy) decision.
Comments
Post a Comment