How to fix ambiguous type on method reference (toString of an Integer)?
There is no way to make method references unambiguous; simply said, method references are a feature that is just supported for unambiguous method references only. So you have two solutions:
use a lambda expression:
Stream.of(1, 32, 12, 15, 23).map(i->Integer.toString(i));
(preferred, at least by me) Use a stream of primitive
int
values when the source consists of primitiveint
values only:IntStream.of(1, 32, 12, 15, 23).mapToObj(Integer::toString);
This will use the static
Integer.toString(int)
method for consuming theint
values.
java Optional interface methods: Ambiguous method reference
You have two possible solutions:
Replace it with a lambda:
this.referenceService.get(id)
.map(ref-> Integer.toString(ref.hashCode()));
use Objects.toString()
this.referenceService.get(id)
.map(Reference::hashCode)
.map(Objects::toString); // this will cal toString method on you hash
Write your own method:
this.referenceService.get(id)
.map(this::toHashString);
private Strign toHashString(Reference ref) {
return Integer.toString(ref.hashCode());
}
How to Resolve Java Method Reference Ambiguity
There is no "collision" :)
The issue is that Number::add
is ambiguous (the compiler - the one in eclipse, at least - reports that correctly).
The ambiguous code:
BiFunction<Number, Integer, Number> m = Number::add;
could either mean:
BiFunction<Number, Integer, Number> m = (x,y) -> Number.add(x,y);
or:
BiFunction<Number, Integer, Number> m = (x,y) -> x.add(y);
Replace this lambda with a method reference
You can't put Integer::toString
because Integer
has two implementations that fit to functional interface Function<Integer, String>
, but you can use String::valueOf
instead:
Stream.iterate(0, i -> i + 1)
.limit(100)
.map(String::valueOf)
.collect(Collectors.toList())
Invoking toString via method reference in Java 8
This has nothing to do with type erasure.
Look at the error message :
(argument mismatch; invalid method reference
reference to toString is ambiguous
both method toString(int) in Integer and method toString() in Integer match)
The Integer
class has two toString
methods that match the functional interface expected by the map()
method. One is static with an int
argument, and the other is the toString()
method that overrides Object
's toString()
.
The compiler doesn't know if you want to execute this :
Arrays.asList(1,2,3).stream().map(i->Integer.toString(i)).forEach(System.out::println);
or this :
Arrays.asList(1,2,3).stream().map(i->i.toString()).forEach(System.out::println);
Concat Stream of String and Integer
The error message should be Ambiguous method reference: both toString() and toString(int) from the type Integer are eligible
. That happens because both toString
and toString(int)
are eligible to be used here.
It could have been both:
.map(i -> i.toString(i))
.map(i -> i.toString())
And it works fine because String::valueOf
has no such overloaded method and thus the compiler is fine with that.
Java 8: Reference to [method] is ambiguous
Your problem is a side-effect of Generalized Target-type Inference, an improvement in Java 8.
What is Target-type Inference
Let's take your example method,
public static <R> R get(String d) {
return (R)d;
}
Now, in the method above, the generic parameter R
cannot be resolved by the compiler because there's no parameter with R
.
So, they introduced a concept called Target-type Inference
, which allows the parameter to be inferred based on the assignment parameter.
So, if you do,
String str = get("something"); // R is inferred as String here
Number num = get("something"); // R is inferred as Number here
This works well in Java 7. But the following does not,
put(get("something");
static void Put(String str) {} //put method
Because type inference worked only for direct assignments.
If there's no direct assignment, then the generic type was inferred as Object
.
So, when you compiled the code with Java 7, your put(Object)
method was called without any problems.
What they did in Java 8
They improved the type inference to infer the type from method calls and chained method calls
More details about them here and here
So now, you can directly call put(get("something"))
and the generic type will be inferred based on the parameter of the put()
method.
But as you know, the methods, put(Charsequence)
and put(char[])
match the arguments. So there's the ambiguity.
Fix?
Just tell the compiler exactly what you want,
put(TestClass.<CharSequence>get("hello")); // This will call the put(CharSequence) method.
Why is this Java method call considered ambiguous?
Your question is very similar to this one.
The short answer is:
Overloaded::genuinelyAmbiguous;
Overloaded::notAmbiguous;
Overloaded::strangelyAmbiguous;
all these method references are inexact (they have multiple overloads). Consequently, according to the JLS §15.12.2.2., they are skipped from the applicability check during overload resolution, which results in ambiguity.
In this case, you need to specify the type explicitly, for example:
load((Processor) Overloaded::genuinelyAmbiguous);
load(( Supplier) Overloaded::strangelyAmbiguous);
Related Topics
Why Does My Sorting Loop Seem to Append an Element Where It Shouldn'T
Using == Operator in Java to Compare Wrapper Objects
Has Been Compiled by a More Recent Version of the Java Runtime (Class File Version 57.0)
Spring Data JPA Update @Query Not Updating
Java.Util.Date Format Ssssss: If Not Microseconds What Are the Last 3 Digits
Java Generics: Cannot Cast List<Subclass> to List<Superclass>
Get All of the Classes in the Classpath
Take N Random Elements from a List<E>
Java: "Final" System.Out, System.In and System.Err
Converting JSON to Xls/CSV in Java
How to Use Regex in String.Contains() Method in Java
Why Can't I Use a Type Argument in a Type Parameter with Multiple Bounds
How to Call a Superclass Method Using Java Reflection
Can "This" Ever Be Null in Java
How to Deploy Javafx Application, Create Jar and Self-Contained Applications and Native Installers