Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 call to generic method is ambiguous [duplicate]

Tags:

java

java-8

I'm porting Java7 code to Java8, and I came up with a following problem. In my codebase I have two methods:

public static <T> ImmutableSet<T> append(Set<T> set, T elem) {
    return ImmutableSet.<T>builder().addAll(set).add(elem).build();
}

public static <T> ImmutableSet<T> append(Set<T> set, Set<T> elemSet) {
    ImmutableSet.Builder<T> newSet = ImmutableSet.builder();
    return newSet.addAll(set).addAll(elemSet).build();

Compiler returns error about ambiguous match for method append in following test:

@Test(expected = NullPointerException.class)
public void shouldAppendThrowNullPointerForNullSecondSet() {
    ImmutableSet<Integer> obj = null;
    CollectionUtils.append(ImmutableSet.of(1), obj);
}

Compiler error:

reference to append is ambiguous both method append(java.util.Set,T) in CollectionUtils and method append(java.util.Set,java.util.Set) in CollectionUtils match

How to rewrite these functions to work with type inference from introduced with Java8?

like image 609
Xter Avatar asked Mar 15 '16 10:03

Xter


1 Answers

You've found the new Generalized Target-type Inference improvements in Java 8. There's a few stack overflow questions on it. Such as this one.

Java 8 can infer the return type of a generic based on the method it's passed to as an argument. So when you call CollectionUtils.append(ImmutableSet.of(1), obj), Java 8 is attempting to return an immutable set from the static of call that matches one of your append methods. In this instance, it could think about returning a ImmutableSet<Object> instead of the ImmutableSet<Integer> that you're clearly trying to return. And then it's unclear if you're calling append(Set<Object>, Object), or append(Set<Integer>, Set<Integer>).

The easiest solution is to rename the second method appendAll. Or, you could follow the suggested fix here and change your call to something like :

CollectionUtils.append(ImmutableSet.<ImmutableSet<Integer>>of(1), obj);

I'd stick with renaming the second method myself though. It will save other developers the same grief when they try to use the library.

like image 176
AndyN Avatar answered Oct 30 '22 17:10

AndyN