xtrakBandit
xtrakBandit

Reputation: 133

Guava Multimaps wildcard putAll

Struggling with a generics issue using Guava's Multimap

class Foo{
    ...
    private Multimap<Baz,? extends Bar> stuff;
    ...

    public void overWriteStuff(Multimap<Baz,? extends Bar> newstuff){
         this.stuff.clear();
         this.stuff.putAll(newStuff);
    }
 }

This looks very straighforward to me, both stuff and the argument newstuff both have the same type yet I get a generics related compiler exception:

The method putAll(Multimap<? extends Baz,? extends capture#8-of ? extends Bar>) in the type Multimap<Baz,capture#8-of ? extends Bar> is not applicable for the arguments (Multimap<Baz,capture#9-of ? extends Bar>)

Can anyone see where my generics screw up is here?

Upvotes: 0

Views: 407

Answers (2)

ColinD
ColinD

Reputation: 110046

The problem is that ? extends Bar means "some specific (but unknown) subtype of Bar". You don't know, for either the field in your class or for the parmater to your method, what actual type of values the multimap holds.

For example, if you have two classes Foo extends Bar and Blah extends Bar, you could assign a Multimap<Baz, Foo> to stuff and pass a Multimap<Baz, Blah> to your method as newstuff. If stuff.putAll(newstuff) were allowed, you'd then have stuff being a multimap that claims all of its values are instances of Foo, when in fact some of them are instead instances of Blah.

Perhaps you actually just want stuff to be a Multimap<Baz, Bar>? In that case its values can be any kind of Bar and your method will work fine. Another option, as @rgettman mentions, is to introduce a type variable T extends Bar to ensure that the values of stuff and newstuff are both the same subtype of Bar; which you do depends on what you're actually trying to accomplish here.

Upvotes: 2

rgettman
rgettman

Reputation: 178263

The ? wildcard from the original declaration cannot match the ? wildcard from the parameter. They could be any subclass of Bar (or Bar itself), and they do not have to match.

You need to introduce a generic type parameter on Foo to replace the wildcards, so that they will represent the same type.

class Foo<T extends Bar>{

In the variable declaration:

private Multimap<Baz, T> stuff;

And in the method parameter:

public void overWriteStuff(Multimap<Baz, T> newstuff){

Incidentally, this has everything to do with Java's generics but nothing to do with Guava. I could replicate the error with a Map replacing the Multimap.

Upvotes: 2

Related Questions