Java – warning: [overloads] method M1 and method M2 have potential uncertainty
import java.util.function.*;
import java.util.function.*; class Test { void test(int foo,Consumer<Integer> bar) { } void test(long foo,Consumer<Long> bar) { } void test(float foo,Consumer<Float> bar) { } void test(double foo,Consumer<Double> bar) { } }
When I use javac - xlint test When compiling it with Java, I got several warnings:
Test.java:4: warning: [overloads] test(int,Consumer<Integer>) in Test is potentially ambiguous with test(long,Consumer<Long>) in Test void test(int foo,Consumer<Integer> bar) { } ^ Test.java:6: warning: [overloads] test(float,Consumer<Float>) in Test is potentially ambiguous with test(double,Consumer<Double>) in Test void test(float foo,Consumer<Float> bar) { } ^ 2 warnings
If I change consumer to supplier, the warning disappears This program is free:
import java.util.function.*; class Test { void test(int foo,supplier<Integer> bar) { } void test(long foo,supplier<Long> bar) { } void test(float foo,supplier<Float> bar) { } void test(double foo,supplier<Double> bar) { } }
Why? What does this warning mean? How fuzzy are these methods? Is it safe to suppress the warning?
Solution
These warnings are due to the interesting intersection between overloaded resolution, target typing, and type inference The compiler thinks ahead for you and warns you that most Lambdas do not have explicitly declared types For example, consider this call:
test(1,i -> { });
What is my type? The compiler cannot infer this until the overload resolution is complete, but a value of 1 matches all four overloads Whichever overload is selected will affect the target type of the second parameter, which in turn will affect the type inferred for I There really isn't enough information for the compiler to decide which method to call, so this line will actually lead to a compile time error:
error: reference to test is ambiguous both method test(float,Consumer<Float>) in Test and method test(double,Consumer<Double>) in Test match
(interestingly, it mentions float and double overloading, but if you comment on one of them, you will get the same long-time overload error.)
Imagine a strategy in which the compiler uses the most specific rules to complete the overload resolution, so as to choose the overload using int arg Then it will have an explicit target type to apply to lambda Compiler designers find this too subtle, and in some cases programmers will be surprised which overload is eventually called Instead of compiling the program in potentially unexpected ways, they think it makes the error safer and forces the programmer to disambiguate
The compiler issues a warning in the method declaration to indicate that a programmer may write code to call one of the methods (as shown above) will cause a compile time error
To disambiguate the call, we had to write one
test(1,(Integer i) -> { });
Or declare some other explicit type for the I parameter Another method is to add a cast before lambda:
test(1,(Consumer<Integer>)i -> { });
But it could be worse You may not want callers of your API to have to fight this at every call point
These warnings do not appear in supplier cases because the type of supplier can be determined by local reasoning without any type of inference
You may want to rethink the way this API is put together If you really want to use methods with these parameter types, you can rename the methods Testint, testlong, etc. and avoid complete overloading Please note that in similar cases, the Java se API has achieved this, such as comparison, length and comparison; Toint, maptolong and maptodouble can also be shown on stream