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

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>