By peakit


2010-04-27 17:16:40 8 Comments

I came across PECS (short for Producer extends and Consumer super) while reading up on generics.

Can someone explain to me how to use PECS to resolve confusion between extends and super?

12 comments

@Premraj 2015-07-26 06:33:49

PECS (Producer extends and Consumer super)

mnemonic → Get and Put principle.

This principle states that:

  • Use an extends wildcard when you only get values out of a structure.
  • Use a super wildcard when you only put values into a structure.
  • And don’t use a wildcard when you both get and put.

In Java, parameters and generic type parameters does not support inheritance as follows.

class Super {
    void testCoVariance(Object parameter){} // method Consumes the Object
    Object testContraVariance(){ return null;} //method Produces the Object
}

class Sub extends Super {
    @Override
    void testCoVariance(String parameter){} //doesn't support eventhough String is subtype of Object

    @Override
    String testContraVariance(){ return null;} //compiles successfully i.e. return type is don't care 
}

Liskov substitution principle: Arrays are covariant(unsafe) but Generics are not i.e. invarient(safe). i.e. Substitution Principle does not work with the parameterized types, meaning that it is illegal to write.
Covariant simply means if X is subtype of Y then X[] will also be sub type of Y[].

Object name= new String("prem"); //works
List<Number> numbers = new ArrayList<Integer>();//gets compile time error

Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
myNumber[0] = 3.14; //attempt of heap pollution i.e. at runtime gets java.lang.ArrayStoreException: java.lang.Double(we can fool compiler but not run-time)

List<String> list=new ArrayList<>();
list.add("prem");
List<Object> listObject=list; //Type mismatch: cannot convert from List<String> to List<Object> at Compiletime  

more examples

bounded(i.e. heading toward somewhere) wildcard : There are 3 different flavours of wildcards:

  • In-variance/Non-variance: ? or ? extends Object - Unbounded Wildcard. It stands for the family of all types. Use when you both get and put.
  • Co-variance: ? extends T (the family of all types that are subtypes of T) - a wildcard with an upper bound. T is the upper-most class in the inheritance hierarchy. Use an extends wildcard when you only Get values out of a structure.
  • Contra-variance: ? super T ( the family of all types that are supertypes of T) - a wildcard with a lower bound. T is the lower-most class in the inheritance hierarchy. Use a super wildcard when you only Put values into a structure.

Note: wildcard ? means zero or one time, represents an unknown type. The wildcard can be used as the type of a parameter, never used as a type argument for a generic method invocation, a generic class instance creation.(i.e. when used wildcard that reference not used in elsewhere in program like we use T)

enter image description here

class Shape { void draw() {}}

class Circle extends Shape {void draw() {}}

class Square extends Shape {void draw() {}}

class Rectangle extends Shape {void draw() {}}

public class TestContraVariance {
 /*
   * Example for an upper bound wildcard (Get values i.e Producer `extends`)
   * 
   * */  

    public void testCoVariance(List<? extends Shape> list) {
        list.add(new Shape()); // Error:  is not applicable for the arguments (Shape) i.e. inheritance is not supporting
        list.add(new Circle()); // Error:  is not applicable for the arguments (Circle) i.e. inheritance is not supporting
        list.add(new Square()); // Error:  is not applicable for the arguments (Square) i.e. inheritance is not supporting
        list.add(new Rectangle()); // Error:  is not applicable for the arguments (Rectangle) i.e. inheritance is not supporting
        Shape shape= list.get(0);//compiles so list act as produces only

        /*You can't add a Shape,Circle,Square,Rectangle to a List<? extends Shape> 
         * You can get an object and know that it will be an Shape
         */         
    }
      /* 
* Example for  a lower bound wildcard (Put values i.e Consumer`super`)
* */
    public void testContraVariance(List<? super Shape> list) {
        list.add(new Shape());//compiles i.e. inheritance is supporting
        list.add(new Circle());//compiles i.e. inheritance is  supporting
        list.add(new Square());//compiles i.e. inheritance is supporting
        list.add(new Rectangle());//compiles i.e. inheritance is supporting
        Shape shape= list.get(0); // Error: Type mismatch, so list acts only as consumer
        Object object= list.get(0); // gets an object, but we don't know what kind of Object it is.

        /*You can add a Shape,Circle,Square,Rectangle to a List<? super Shape> 
        * You can't get an Shape(but can get Object) and don't know what kind of Shape it is.
        */  
    }
}

generics and examples

@Lonely Neuron 2018-04-29 06:12:53

Hey, I just wanted to know what you meant with the last sentense: "If you think my analogy is wrong please update". Do you mean if it is ethically wrong (which is subjective) or if it is wrong in the context of programming (which is objective: no, it's not wrong)? I would like to replace it with a more neutral example which is universally acceptable independent of cultural norms and ethical believes; If that is OK with you.

@Farrukh Chishti 2019-02-07 15:33:37

Covariance: accept subtypes
Contravariance: accept supertypes

Covariant types are read-only, while contravariant types are write-only.

@Pradeep Kr Kaushal 2014-11-13 06:51:24

In a nutshell, three easy rules to remember PECS:

  1. Use the <? extends T> wildcard if you need to retrieve object of type T from a collection.
  2. Use the <? super T> wildcard if you need to put objects of type T in a collection.
  3. If you need to satisfy both things, well, don’t use any wildcard. As simple as that.

@anoopelias 2013-11-02 06:34:38

The principles behind this in computer science is called

  • Covariance: ? extends MyClass,
  • Contravariance: ? super MyClass and
  • Invariance/non-variance: MyClass

The picture below should explain the concept.

Picture courtesy: Andrey Tyukin

Covariance vs Contravariance

@Andrey Tyukin 2014-06-15 23:11:38

Hey everyone. I'm Andrey Tyukin, I just wanted to confirm that anoopelias & DaoWen contacted me and obtained my permission to use the sketch, it's licensed under (CC)-BY-SA. Thx @ Anoop for giving it a second life^^ @Brian Agnew: (on "few votes"): That's because it's a sketch for Scala, it uses Scala syntax and assumes declaration-site variance, which is quite different to Java's weird call-site variance... Maybe I should write a more detailed answer that clearly shows how this sketch applies to Java...

@cs4r 2017-05-01 12:35:52

This is one of the simplest and clearest explanations for Covariance and Contravariance that I have ever found!

@slouc 2017-06-02 08:06:53

@Andrey Tyukin Hi, I also want to use this image. How can I contact you?

@Andrey Tyukin 2017-06-02 17:16:17

If you have any questions about this illustration, we can discuss them in the chatroom: chat.stackoverflow.com/rooms/145734/…

@Dmitry Ziyatdinov 2017-08-13 13:25:24

Cool graphics, though I don't understand the notation: "Consumer of everythiing" < "Consumer of vegetables". And on the other hand: "Producer of entertainment" > "Producer of music". Shouldn't it be reversed?

@Chetan Gowda 2018-05-21 09:38:42

Can someone explain the use/application of <? super MyClass>. Because you can put MyClass and its subclass objects into it, but if you want to take out stuff from that collection. They can be taken out only as Objects.

@Andrey Tyukin 2018-08-11 11:58:38

@ChetanGowda Here is a rather detailed example that explains why <? super X> is useful, and what happens if you omit it: Java 8 Comparator comparing() static function.

@contrapost 2018-11-20 13:47:41

Using real life example (with some simplifications):

  1. Imagine a freight train with freight cars as analogy to a list.
  2. You can put a cargo in a freight car if the cargo has the same or smaller size than the freight car = <? super FreightCarSize>
  3. You can unload a cargo from a freight car if you have enough place (more than the size of the cargo) in your depot = <? extends DepotSize>

@Daniel 2018-09-23 17:42:34

Let's assume this hierarchy:

class Creature{}// X
class Animal extends Creature{}// Y
class Fish extends Animal{}// Z
class Shark extends Fish{}// A
class HammerSkark extends Shark{}// B
class DeadHammerShark extends HammerSkark{}// C

Let's clarify PE - Producer Extends:

List<? extends Shark> sharks = new ArrayList<>();

Why you cannot add objects that extend "Shark" in this list? like:

sharks.add(new HammerShark());//will result in compilation error

Since you have a list that can be of type A, B or C at runtime, you cannot add any object of type A, B or C in it because you can end up with a combination that is not allowed in java.
In practice, the compiler can indeed see at compiletime that you add a B:

sharks.add(new HammerShark());

...but it has no way to tell if at runtime, your B will be a subtype or supertype of the list type. At runtime the list type can be any of the types A, B, C. So you cannot end up adding HammerSkark (super type) in a list of DeadHammerShark for example.

*You will say: "OK, but why can't I add HammerSkark in it since it is the smallest type?". Answer: It is the smallest you know. Buy HammerSkark can be extended too by somebody else and you end up in the same scenario.

Let's clarify CS - Consumer Super:

In the same hierarchy we can try this:

List<? super Shark> sharks = new ArrayList<>();

What and why you can add to this list?

sharks.add(new Shark());
sharks.add(new DeadHammerShark());
sharks.add(new HammerSkark());

You can add the above types of objects because anything below shark(A,B,C) will always be subtypes of anything above shark (X,Y,Z). Easy to understand.

You cannot add types above Shark, because at runtime the type of added object can be higher in hierarchy than the declared type of the list(X,Y,Z). This is not allowed.

But why you cannot read from this list? (I mean you can get an element out of it, but you cannot assign it to anything other than Object o):

Object o;
o = sharks.get(2);// only assignment that works

Animal s;
s = sharks.get(2);//doen't work

At runtime, the type of list can be any type above A: X, Y, Z, ... The compiler can compile your assignment statement (which seems correct) but, at runtime the type of s (Animal) can be lower in hierarchy than the declared type of the list(which could be Creature, or higher). This is not allowed.

To sum up

We use <? super T> to add objects of types equal or below T in list. We cannot read from it.
We use <? extends T> to read objects of types equal or below T from list. We cannot add element to it.

@Jason 2018-02-19 09:50:08

Remember this:

Consumer eat supper(super); Producer extends his parent's factory

@ColinD 2010-04-27 17:32:52

As I explain in my answer to another question, PECS is a mnemonic device created by Josh Bloch to help remember Producer extends, Consumer super.

This means that when a parameterized type being passed to a method will produce instances of T (they will be retrieved from it in some way), ? extends T should be used, since any instance of a subclass of T is also a T.

When a parameterized type being passed to a method will consume instances of T (they will be passed to it to do something), ? super T should be used because an instance of T can legally be passed to any method that accepts some supertype of T. A Comparator<Number> could be used on a Collection<Integer>, for example. ? extends T would not work, because a Comparator<Integer> could not operate on a Collection<Number>.

Note that generally you should only be using ? extends T and ? super T for the parameters of some method. Methods should just use T as the type parameter on a generic return type.

@Fatih Arslan 2019-02-07 14:26:04

Does this principle only hold for Collections? It makes sense when one tries to correlate it with a list. If you think about the signature of sort(List<T>,Comparator<? super T>) ---> here the Comparator uses super so it means it is a consumer in PECS context. When you look at the implementation for instance like : public int compare(Person a, Person b) { return a.age < b.age ? -1 : a.age == b.age ? 0 : 1; } I feel like Person does not consume anything but produces age. That makes me confused. Is there a flaw in my reasoning or PECS only holds for Collections?

@Andrejs 2017-05-17 18:12:22

(adding an answer because never enough examples with Generics wildcards)

       // Source 
       List<Integer> intList = Arrays.asList(1,2,3);
       List<Double> doubleList = Arrays.asList(2.78,3.14);
       List<Number> numList = Arrays.asList(1,2,2.78,3.14,5);

       // Destination
       List<Integer> intList2 = new ArrayList<>();
       List<Double> doublesList2 = new ArrayList<>();
       List<Number> numList2 = new ArrayList<>();

        // Works
        copyElements1(intList,intList2);         // from int to int
        copyElements1(doubleList,doublesList2);  // from double to double


     static <T> void copyElements1(Collection<T> src, Collection<T> dest) {
        for(T n : src){
            dest.add(n);
         }
      }


     // Let's try to copy intList to its supertype
     copyElements1(intList,numList2); // error, method signature just says "T"
                                      // and here the compiler is given 
                                      // two types: Integer and Number, 
                                      // so which one shall it be?

     // PECS to the rescue!
     copyElements2(intList,numList2);  // possible



    // copy Integer (? extends T) to its supertype (Number is super of Integer)
    private static <T> void copyElements2(Collection<? extends T> src, 
                                          Collection<? super T> dest) {
        for(T n : src){
            dest.add(n);
        }
    }

@Michael Myers 2010-04-27 17:37:26

tl;dr: "PECS" is from the collection's point of view. If you are only pulling items from a generic collection, it is a producer and you should use extends; if you are only stuffing items in, it is a consumer and you should use super. If you do both with the same collection, you shouldn't use either extends or super.


Suppose you have a method that takes as its parameter a collection of things, but you want it to be more flexible than just accepting a Collection<Thing>.

Case 1: You want to go through the collection and do things with each item.
Then the list is a producer, so you should use a Collection<? extends Thing>.

The reasoning is that a Collection<? extends Thing> could hold any subtype of Thing, and thus each element will behave as a Thing when you perform your operation. (You actually cannot add anything to a Collection<? extends Thing>, because you cannot know at runtime which specific subtype of Thing the collection holds.)

Case 2: You want to add things to the collection.
Then the list is a consumer, so you should use a Collection<? super Thing>.

The reasoning here is that unlike Collection<? extends Thing>, Collection<? super Thing> can always hold a Thing no matter what the actual parameterized type is. Here you don't care what is already in the list as long as it will allow a Thing to be added; this is what ? super Thing guarantees.

@Feuermurmel 2013-05-07 13:11:56

I'm always trying to think about it this way: A producer is allowed to produce something more specific, hence extends, a consumer is allowed to accept something more general, hence super.

@Raman 2014-01-24 19:20:58

Another way to remember the producer/consumer distinction is to think of a method signature. If you have a method doSomethingWithList(List list), you are consuming the list and so will need covariance / extends (or an invariant List). On the other hand if your method is List doSomethingProvidingList, then you are producing the List and will need contravariance / super (or an invariant List).

@Chatterjee 2014-05-24 06:27:26

@MichaelMyers: Why can't we simply use a parameterized type for both these cases? Is there any specific advantage of using wildcards here, or is it just a means of improving readability similar to, say, using references to const as method parameters in C++ to signify that the method does not modify the arguments?

@masterxilo 2014-05-27 19:08:07

@Raman, I think you just confused it. In doSthWithList( you can have List<? super Thing> ), since you are a consumer, you can use super (remember, CS). However, it's List<? extends Thing> getList() since you are allowed to return something more specific when producing (PE).

@H.Rabiee 2014-10-23 14:33:38

what if we want to go through and add to the collection?

@biziclop 2015-05-18 13:37:49

@hajder Then your only option is to use the exact type: Collection<Thing>. The reason for this is that you must be sure that the get method will return something that you can cast to Thing, and the add method accepts a Thing, which it can cast to the actual element type. The only type that satisfies both criteria is Thing itself.

@biziclop 2015-05-18 13:41:02

@hajder Though note that here "going through" assumes that you really need to cast the elements to Thing.

@Janus Varmarken 2016-02-11 13:40:46

@Chatterjee: the reason for using wildcards is flexibility. By declaring that a parameter is of type Collection<? super Thing> you give the caller more flexibility as she can invoke your method not only with a Collection<Thing> as an argument but also with a Collection<SomeSupertypeOfThing> as an argument.

@Eric Zhang 2017-05-30 01:59:30

@MichaelMyers: For the case2, Collection <? super Thing> also is iterable, right?

@Michael Myers 2017-06-01 00:20:11

@EricZhang: When you are adding to a collection, it does not matter whether or not the collection is iterable.

@AZ_ 2018-05-30 13:54:01

PECS is counter intuitive, If I am taking something from the list so I am consuming items or producing?

@Prateek 2014-01-25 13:39:13

PECS (short for "Producer extends and Consumer super") can be explained by : Get and Put Principle

Get And Put Principle (From Java Generics and Collections)

It states,

  1. use an extends wildcard when you only get values out of a structure
  2. use a super wildcard when you only put values into a structure
  3. and don’t use a wildcard when you both get and put.

Let's understand it by example:

1. For Extends Wildcard(get values i.e Producer extends)

Here is a method, that takes a collection of numbers, converts each to a double, and sums them up

public static double sum(Collection<? extends Number> nums) {
   double s = 0.0;
   for (Number num : nums) 
      s += num.doubleValue();
   return s;
}

Let's call the method :

List<Integer>ints = Arrays.asList(1,2,3);
assert sum(ints) == 6.0;
List<Double>doubles = Arrays.asList(2.78,3.14);
assert sum(doubles) == 5.92;
List<Number>nums = Arrays.<Number>asList(1,2,2.78,3.14);
assert sum(nums) == 8.92;

Since, sum() method uses extends, all of the following calls are legal. The first two calls would not be legal if extends was not used.

EXCEPTION : You cannot put anything into a type declared with an extends wildcard—except for the value null, which belongs to every reference type:

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(null);  // ok
assert nums.toString().equals("[1, 2, null]");

2. For Super Wildcard(put values i.e Consumer super)

Here is a method, that takes a collection of numbers and an int n, and puts the first n integers, starting from zero, into the collection:

public static void count(Collection<? super Integer> ints, int n) {
    for (int i = 0; i < n; i++) ints.add(i);
}

Let's call the method :

List<Integer>ints = new ArrayList<Integer>();
count(ints, 5);
assert ints.toString().equals("[0, 1, 2, 3, 4]");
List<Number>nums = new ArrayList<Number>();
count(nums, 5); nums.add(5.0);
assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]");
List<Object>objs = new ArrayList<Object>();
count(objs, 5); objs.add("five");
assert objs.toString().equals("[0, 1, 2, 3, 4, five]");

Since, count() method uses super, all of the following calls are legal: The last two calls would not be legal if super was not used.

EXCEPTION : you cannot get anything out from a type declared with a super wildcard—except for a value of type Object, which is a supertype of every reference type:

List<Object> objs = Arrays.<Object>asList(1,"two");
List<? super Integer> ints = objs;
String str = "";
for (Object obj : ints) str += obj.toString();
assert str.equals("1two");

3. When both Get and Put, don't Use wildcard

Whenever you both put values into and get values out of the same structure, you should not use a wildcard.

public static double sumCount(Collection<Number> nums, int n) {
   count(nums, n);
   return sum(nums);
}

@Gab 2013-10-07 18:15:13

public class Test {

    public class A {}

    public class B extends A {}

    public class C extends B {}

    public void testCoVariance(List<? extends B> myBlist) {
        B b = new B();
        C c = new C();
        myBlist.add(b); // does not compile
        myBlist.add(c); // does not compile
        A a = myBlist.get(0); 
    }

    public void testContraVariance(List<? super B> myBlist) {
        B b = new B();
        C c = new C();
        myBlist.add(b);
        myBlist.add(c);
        A a = myBlist.get(0); // does not compile
    }
}

@Saurabh Patil 2016-05-30 03:47:48

So "? extends B" should be interpreted as "? B extends". It's something that B extends so that would include all the super classes of B up to Object, excluding B itself. Thanks for the code!

@asgs 2016-09-28 06:16:13

@SaurabhPatil No, ? extends B means B and anything extending B.

Related Questions

Sponsored Content

14 Answered Questions

[SOLVED] Difference between <? super T> and <? extends T> in Java

22 Answered Questions

[SOLVED] What is a serialVersionUID and why should I use it?

21 Answered Questions

[SOLVED] What is reflection and why is it useful?

6 Answered Questions

[SOLVED] What does 'super' do in Python?

25 Answered Questions

[SOLVED] Create instance of generic type in Java?

  • 2008-09-16 18:04:28
  • David Citron
  • 398513 View
  • 527 Score
  • 25 Answer
  • Tags:   java generics

41 Answered Questions

[SOLVED] "implements Runnable" vs "extends Thread" in Java

4 Answered Questions

[SOLVED] Java generics PECS

7 Answered Questions

[SOLVED] super() raises "TypeError: must be type, not classobj" for new-style class

7 Answered Questions

[SOLVED] Understanding Python super() with __init__() methods

2 Answered Questions

[SOLVED] regarding PECS java generics

  • 2010-12-26 23:55:05
  • Billworth Vandory
  • 2151 View
  • 1 Score
  • 2 Answer
  • Tags:   java generics

Sponsored Content