How to Fix Ambiguous Type on Method Reference (Tostring of an Integer)

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:

  1. use a lambda expression:

    Stream.of(1, 32, 12, 15, 23).map(i->Integer.toString(i));
  2. (preferred, at least by me) Use a stream of primitive int values when the source consists of primitive int values only:

    IntStream.of(1, 32, 12, 15, 23).mapToObj(Integer::toString);

    This will use the static Integer.toString(int) method for consuming the int 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



Leave a reply



Submit