0

Say I have the following two classes:

public class SomethingElse<A, B> {

    public List<? extends Something<A, B>> getOneList() {
        //doesn't matter
    }

    public List<? extends Something<A, B>> getAnotherList() {
        //doesn't matter
    }

}

public class Something<A, B> {
    //doesn't matter
}

I would like to merge the results that I get from getOneList() and getAnotherList():

SomethingElse<String, Integer> somethingElse = new SomethingElse<>();
List<? extends Something<String, Integer>> oneList = somethingElse.getOneList();
List<? extends Something<String, Integer>> anotherList = somethingElse.getAnotherList();
anotherList.forEach(e -> oneList.add(e)); //<-- DOESN'T COMPILE

However, the compiler complains that in the .add() method above, it is expecting capture of ? extends Something<String, Integer> but I am providing... well, capture of ? extends Something<String, Integer>:

enter image description here

I feel this has something to see with type erasure but I can't figure out why, even the compiler itself is unable to produce a clear message since it's telling me I'm providing type X but it's expecting type X.

Can anyone explain me technically why the compiler doesn't like this? What are the possible wrong mixes I may be doing into the same list?

Matteo NNZ
  • 11,930
  • 12
  • 52
  • 89

1 Answers1

2

Are you really going to subclass those two classes such that you need the extends? You could do it like this, sans the extends. I recommend you read this because using extends vs super dictates whether you can add or remove items from a list.

SomethingElse<String, Integer> somethingElse =
        new SomethingElse<>();
List<Something<String, Integer>> oneList =
        somethingElse.getOneList();
List<Something<String, Integer>> anotherList =
        somethingElse.getAnotherList();
    
anotherList.addAll(oneList);



class SomethingElse<A, B> {
    
    public List<Something<A, B>> getOneList() {
        return null;
    }
    
    public List<Something<A, B>> getAnotherList() {
        return null;
    }
    
}

class Something<A, B> {
    // doesn't matter
}
WJS
  • 36,363
  • 4
  • 24
  • 39
  • I can't modify the SomethingElse class. Though, I've tried to remove both super and extends, it works fine even if I need an unchecked cast. Any idea to avoid it? – Matteo NNZ Jan 04 '22 at 17:34
  • Unfortunately, this is a problem with wildcards and the contravariant and reification nature of generics. For more info you may want to check out this article on [Covariance vs Contravariance](https://dzone.com/articles/covariance-and-contravariance). It also talks about the get/put principle which is aka PECs. It may give some ideas on how to handle your specific situation. – WJS Jan 04 '22 at 18:06