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
?
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
?
In a nutshell, three easy rules to remember PECS:
<? extends T>
wildcard if you need to retrieve object of typeT
from a collection.<? super T>
wildcard if you need to put objects of typeT
in a collection.PECS (Producer
extends
and Consumersuper
)mnemonic → Get and Put principle.
This principle states that:
Example in Java:
Liskov substitution principle: if S is a subtype of T, then objects of type T may be replaced with objects of type S.
Within the type system of a programming language, a typing rule
Covariance and contravariance
To illustrate this general phenomenon, consider the array type. For the type Animal we can make the type Animal[]
Java Examples:
more examples
bounded(i.e. heading toward somewhere) wildcard : There are 3 different flavours of wildcards:
?
or? extends Object
- Unbounded Wildcard. It stands for the family of all types. Use when you both get and put.? extends T
(the family of all types that are subtypes ofT
) - a wildcard with an upper bound.T
is the upper-most class in the inheritance hierarchy. Use anextends
wildcard when you only Get values out of a structure.? super T
( the family of all types that are supertypes ofT
) - a wildcard with a lower bound.T
is the lower-most class in the inheritance hierarchy. Use asuper
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 useT
)generics and examples
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 usesuper
. If you do both with the same collection, you shouldn't use eitherextends
orsuper
.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 ofThing
, and thus each element will behave as aThing
when you perform your operation. (You actually cannot add anything to aCollection<? extends Thing>
, because you cannot know at runtime which specific subtype ofThing
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 aThing
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 aThing
to be added; this is what? super Thing
guarantees.Remember this:
Using real life example (with some simplifications):
<? super FreightCarSize>
<? extends DepotSize>
As I explain in my answer to another question, PECS is a mnemonic device created by Josh Bloch to help remember Producer
extends
, Consumersuper
.Note that generally you should only be using
? extends T
and? super T
for the parameters of some method. Methods should just useT
as the type parameter on a generic return type.