Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Incompatible generic wildcard captures

in the following snippet:

package test;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

public class WildcardsTest<K, V> {
    private Iterator<Map.Entry<K, ? extends Collection<V>>> iterator;
    public WildcardsTest(Map<K, ? extends Collection<V>> map) {
        iterator = map.entrySet().iterator();
        /* Type mismatch: cannot convert from
           Iterator<Map.Entry<K,capture#1-of ? extends Collection<V>>> to
           Iterator<Map.Entry<K,? extends Collection<V>>> */
    }
}

The assignment is incorrect, although the types seem to match exactly.

I've devised a dirty workaround by specifying the type of the Collection as another generic parameter, like this:

public class WildcardsTest<K, V, C extends Collection<V>> {
    private Iterator<Map.Entry<K, C>> iterator;
    public WildcardsTest(Map<K, C> map) {
        iterator = map.entrySet().iterator();
    }
}

But that C parameter is really a "don't care" type that only complicates the API, is there any way to get rid of it while maintaining type safety?

Thanks.

like image 730
fortran Avatar asked Jan 01 '26 01:01

fortran


2 Answers

Do it like this and it will work:

private final Iterator<? extends
    Map.Entry<K, ? extends Collection<V>>
> iterator;

You can still use the iterator like this:

public void foo(){
    while(iterator.hasNext()){
        Entry<K, ? extends Collection<V>> entry = iterator.next();
        Collection<V> value = entry.getValue();
    }
}

For reference, read the get and put principle (originally from Java Generics and Collections)

like image 106
Sean Patrick Floyd Avatar answered Jan 02 '26 14:01

Sean Patrick Floyd


The assignment is incorrect, although the types seem to match exactly.

The two ?-wildcards can be bound to two different classes. Put it this way, it is quite obvious that there is a type mismatch:

private Iterator<Map.Entry<K, ArrayList<V>>> iterator;
public WildcardsTest(Map<K, HashSet<V>> map) {
    iterator = map.entrySet().iterator();
}

When you introduce the C, you "force them" to refer to the same class.

like image 32
aioobe Avatar answered Jan 02 '26 14:01

aioobe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!