user2418306
user2418306

Reputation: 2382

Method with ? extends Collections<String> is not applicable for Set<String>

Short, self contained, non-compilable example:

public void test1() throws Exception {
    Map<String, Map<String, Set<String>>> a = Collections.singletonMap("One",
            Collections.singletonMap("Two", new HashSet<String>()));
    foo(a);
}

void foo(Map<String, Map<String, ? extends Collection<String>>> x) {
}

Yields (javac 1.8.0_102):

error: incompatible types: Map<String,Map<String,Set<String>>> cannot be converted to Map<String,Map<String,? extends Collection<String>>>
            foo(a);
                ^

I expect foo to take any subtype of Collection like Set or List. What is wrong with code above?

Upvotes: 2

Views: 200

Answers (3)

Malt
Malt

Reputation: 30335

Your code doesn't compile for the same reason the following (simpler) code doesn't compile:

List<Integer> l = Arrays.asList(1,2,3);
foo(l); //The method v(List<Object>) in the type Test is not applicable for the arguments (List<Integer>)

public void foo (List<Object> a){
...
}

The fact that Integer extends Object doesn't mean that List<Integer> extends List<Object>. They're two different, unrelated, types.

We can fix the compilation error in the simple case by changing foo's signature to:

public void foo (List<? extends Object> a){
 ...
}

This tells the compiler that foo will be accepting a List of something that extends Object, which is what List<Integer> is.

In your case, Map<String, Map<String, Set<String>>> doesn't extend Map<String, Map<String, ? extends Collection<String>>>.

Even if you changed your foo to void foo(Map<String, Object> x) it wouldn't compile since Map<String, Map<String, Set<String>>> does not extend Map<String, Object>. They're two different types.

To get it to work, you can change foo's signature to void foo(Map<String, ? extends Map<String, ? extends Collection<String>>> x)

Upvotes: 3

Calculator
Calculator

Reputation: 2789

The way you declared foo, the compiler demands a type parameter of the exact type Map<String, ? extends Collection<String>>. You could make foo generic:

<C extends Collection<String>> void  foo(Map<String, Map<String, C>> x) {
}

Upvotes: 3

lukeg
lukeg

Reputation: 4399

This compiles

void foo(Map<String, ? extends Map<String, ? extends Collection<String>>> x)

Upvotes: 2

Related Questions