What does the PECS mnemonic stand for, and how do you decide between `? extends T` and `? super T`?
answer
- Producer Extends, Consumer Super
- extends = read-only (out), super = write-only (in)
- Collections.copy(dest super, src extends)
- both produce and consume -> plain T
- invariance is why wildcards exist
basics
~10 sPECS means Producer Extends, Consumer Super. If a structure gives you (produces) values, use ? extends T. If it receives the values you put in (consumes them), use ? super T.
solid answer
~40 sPECS stands for "Producer Extends, Consumer Super." It is a rule for picking the right bounded wildcard. If a generic parameter is a source you only read T values out of, declare it `? extends T` (a producer). If it is a sink you only write T values into, declare it `? super T` (a consumer). The canonical example is `Collections.copy(List<? super T> dest, List<? extends T> src)`: the source produces, so `extends`; the destination consumes, so `super`. The payoff is flexibility: `? extends Number` accepts `List<Integer>` and `List<Double>`; `? super Integer` accepts `List<Number>` and `List<Object>`. If a parameter both produces and consumes T, use an exact `List<T>` with no wildcard.
code
java · 10 lines// Producer Extends, Consumer Super
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dest.set(i, src.get(i)); // read src (produces), write dest (consumes)
}
}
List<Number> dest = new ArrayList<>(List.of(0, 0, 0));
List<Integer> src = List.of(1, 2, 3);
copy(dest, src); // works: Number super Integer, Integer extends Integergo deeper
Knows the words "Producer Extends, Consumer Super" and that extends is for reading and super is for writing.
Can apply PECS to a method signature, explains why a producer is read-only and a consumer is write-only, and recognizes when no wildcard is needed.
Connects PECS to generic invariance and type-safety proofs, designs flexible API signatures, and knows to avoid wildcards in return types.
Sets team conventions on wildcard usage at API boundaries, weighs flexibility vs. caller burden, and reasons about variance across the codebase and library design.
## The problem PECS solves Java generics are **invariant**: `List<Integer>` is *not* a subtype of `List<Number>`, even though `Integer` is a subtype of `Number`. The reason is safety. If `List<Integer>` were assignable to `List<Number>`, you could call `add(3.14)` (a `Double`) on it and corrupt a list meant to hold only `Integer`s. So Java forbids it. That invariance makes generic methods rigid: a method taking `List<Number>` rejects a `List<Integer>` argument. **Bounded wildcards** restore flexibility while keeping safety. ## The two bounded wildcards - **`? extends T`** — "some unknown type that is T or a subtype of T." `List<? extends Number>` could really be a `List<Integer>` or a `List<Double>`. Because the compiler does not know *which* subtype, it lets you **read** elements (they are guaranteed to be at least a `Number`) but **forbids adding** anything except `null` (you cannot prove a `Double` belongs in what might be a `List<Integer>`). This is a **producer**: it hands T values out. - **`? super T`** — "some unknown type that is T or a supertype of T." `List<? super Integer>` could be a `List<Integer>`, `List<Number>`, or `List<Object>`. You can safely **add** an `Integer` (it fits any of those), but **reading** gives back only `Object`, because you do not know how far up the hierarchy the real type is. This is a **consumer**: it takes T values in. ## The mnemonic **P**roducer **E**xtends, **C**onsumer **S**uper, coined by Joshua Bloch in *Effective Java*. Ask: *from the method's point of view, does this parameter produce T's (give them to me) or consume T's (receive them from me)?* - Produces T → `? extends T` - Consumes T → `? super T` - Both (read and write the same T) → plain `T`, no wildcard. - Neither / does not involve T at all → no wildcard needed. ## Worked example: Collections.copy ```java public static <T> void copy(List<? super T> dest, List<? extends T> src) ``` The `src` list is read from — it **produces** T's — so `? extends T`. The `dest` list is written to — it **consumes** T's — so `? super T`. With this signature you can copy a `List<Integer>` into a `List<Number>`, which would be impossible with plain `List<T>` for both. ## Why the asymmetry of read/write The restriction falls out of what the compiler can *prove*. With `? extends T` the lower edge of the real type is unknown, so writing is unsafe but the upper bound T is known, so reading is safe. With `? super T` the upper edge is unknown (reads degrade to `Object`) but T is a guaranteed lower bound, so writing a T is safe. Reading from a producer and writing to a consumer are exactly the safe operations — hence PECS. ## When NOT to use a wildcard If a parameter is both produced from and consumed into with the same type variable, you need an exact type `List<T>`. Also, return types should generally not use wildcards — they force the caller to deal with wildcards too. Wildcards are a tool for input flexibility.
- Can you add elements to a `List<? extends Number>`?No — except the literal `null`. The compiler does not know the actual element type (could be `List<Integer>`), so it cannot prove any concrete value is safe to add.
- What type comes back when you read from a `List<? super Integer>`?`Object`. The actual list could be `List<Object>`, so the only guaranteed upper bound for a read is `Object`.
saying these in an interview costs you the question
- Saying you can add arbitrary elements to a `? extends T` list (you can only add null)
- Confusing the direction: using extends for the destination/consumer
- Claiming `List<Integer>` is a subtype of `List<Number>` (generics are invariant)
- Thinking reading from a `? super T` list gives back T (it gives Object)