0

I am noticing some odd behavior when using bounded wildcards. When I use a bounded wildcard as a method parameter, I see the expected behavior. This code takes a list of RuntimeException or its subclasses and prints them:

public static void foo(List<? extends RuntimeException> exceptions) {
    for (RuntimeException ex : exceptions) {
        System.out.println(ex);
    }
}

When passing a list of unchecked exceptions, it prints them out without issue.

However, when using a bounded wildcard outside of a method parameter, it seems to apply the opposite of whatever bound is stated (if I write extends, it is treated as super and vice versa).

public static void main(String[] args) {
    List<? extends RuntimeException> arr = new ArrayList<>();
    arr.add(new IllegalArgumentException()); // DOES NOT COMPILE
}

The compiler complains: java: incompatible types: java.lang.StringIndexOutOfBoundsException cannot be converted to capture#1 of ? extends java.lang.RuntimeException

When I change List<? extends RuntimeException> to List<? super RuntimeException>, the code compiles without error when given a subclass of RuntimeException. This is the opposite of what I expected to happen. Can anyone explain this behavior?

Edit: no objects can be added to a list declared with a bounded wildcard. The second example fails to compile because it is using the add() method. Explained here.

Mark Rotteveel
  • 82,132
  • 136
  • 114
  • 158
avittoria
  • 23
  • 4
  • 2
    Does [this](https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java) answer your question? – Adarsh Apr 10 '21 at 07:20
  • This is not Java 11 problem as stated in your question, it is expected behaviour as per the docs. – code_mechanic Apr 10 '21 at 07:25
  • @Adarsh perfect explanation, thanks! – avittoria Apr 10 '21 at 07:29
  • 1
    You seem to associate the type `List extends RuntimeException>` with the explanation "takes a list of RuntimeException or its subclasses". This is somewhat misleading. The shown declaration uses a list with a (nearly) _unknown_ type parameter ... that is what the `?` really means. The only thing you know is that the (still unknown) type parameter must be a subtype of `RuntimeException`. So a `List` would fit, but also a `List`, or also a `List`. – Seelenvirtuose Apr 10 '21 at 07:39
  • 1
    And that means that the compiler cannot allow a call `arr.add(new IllegalArgumentException())`, because it simply cannot know the type parameter with which the list was initialized. – Seelenvirtuose Apr 10 '21 at 07:40
  • 1
    You still can add `null` to a `List extends RuntimeException>`. – Holger Apr 12 '21 at 10:24

0 Answers0