1

I have read through several posts on here about this topics.

This was a especially a good post

I thought I understood the PECS-concept, and tried to set up a small example to test it out.

import java.util.Map;
import java.util.HashMap;

class Test {
    public static void main(String[] args) {
        Map<String, ? super Number> map = new HashMap<>();
        map.put("int", 1);
        map.put("double", 1.0);
        map.put("long", 100000000000L);

        print(map);

    }

    public static void print(Map<String, ? extends Number> map) {
        map.forEach((k, v) -> System.out.printf("Key: %s, Val: %s%n", k, v));
    }
}

I know I need to use super to be able to insert multiple subtypes in to the same map.

But when it comes to printing. I thought using extends would be sufficient, since PECS (Producer extends)

Instead I get this:

Error:(12, 15) java: incompatible types: java.util.Map<java.lang.String,capture#1 of ? super java.lang.Number> cannot be converted to java.util.Map<java.lang.String,? extends java.lang.Number>
Nilzone-
  • 2,646
  • 5
  • 31
  • 67
  • 2
    There'sā€‹ no problem with the `print()` method; the problem is what you're trying to pass into it. What if `map` is `Map`? ā€“ shmosel May 25 '17 at 08:20
  • 3
    You map is both a producer, and a consumer of Number, so its generic type must both extend Number, and super Number. There is only one type that can do that: Number. So it should be a Map. ā€“ JB Nizet May 25 '17 at 08:23
  • 2
    As a rule of thumb, it's usually a bad idea to instantiate a collection with a wildcard type. You'll almost always want to read from *and* write to said collection. ā€“ shmosel May 25 '17 at 08:28

2 Answers2

1

In both cases Number suffices and is most adequate.

As said super does not make sense; you could just as well have written Object.

Map<String, Number> map = new HashMap<>();

With this you may put a Number or a child of Number into the map. Or get a Number or a parent of Number from the map.

Now if you would use:

public static void print(Map<String, ? extends Number> map) {

you cannot put a Double (or whatever) into that map as the actual map argument could have been a Map<String, Integer>. Hence Map<String, Number>.

As the type system of java is not very strong/expressive, a good rule is to keep extends for meta level constructs (=when you need them). For simple data structures PECS follows from the data flow.

Joop Eggen
  • 96,344
  • 7
  • 73
  • 121
0

This is because

    Map<String, ? super Number> map

may contain any values, try this

Map<String, Object> map1 = new HashMap<>();
map1.put("1", "2");
Map<String, ? super Number> map = map1;

there is no compile error

Evgeniy Dorofeev
  • 124,221
  • 27
  • 187
  • 258