Explain the PECS rule and why a method that copies elements into a destination should declare it as `List<? super T>`.
answer
- Producer Extends, Consumer Super
- read → extends; write → super
- both read+write → exact T
- copy: dest super, src extends
- never wildcard a return type
basics
~20 sPECS means "Producer Extends, Consumer Super." Something you read from uses extends; something you write to uses super. A copy destination is written to (a consumer), so it should be List<? super T> to accept T and its subtypes.
solid answer
~40 sPECS — Producer Extends, Consumer Super — is Joshua Bloch's mnemonic for choosing wildcards on API parameters. If a parameter *produces* values you read out, use `<? extends T>` so any subtype source is accepted. If it *consumes* values you write in, use `<? super T>` so any supertype destination is accepted. A copy method does both: it reads from a source (producer → `<? extends T>`) and writes into a destination (consumer → `<? super T>`). Declaring the destination as `List<? super T>` makes the API maximally flexible — you can copy a `List<Integer>` into a `List<Number>` or a `List<Object>` — while staying type-safe, because writing a T (or subtype) into a slot that holds a supertype of T is always valid. The JDK's `Collections.copy`, `addAll`, and `fill` follow exactly this pattern.
go deeper
Can recite PECS as a phrase and pick super for a write parameter when prompted.
Applies PECS to a copy/addAll method correctly and explains read-vs-write reasoning.
Designs flexible generic APIs with PECS, cites JDK examples, and knows not to wildcard return types.
Weighs API ergonomics vs. complexity, decides where wildcards are worth it, and relates PECS to declaration-site variance in other languages.
## The problem PECS solves Java generics are **invariant**: `List<Integer>` is not a subtype of `List<Number>`. This keeps the type system sound but makes generic *methods* rigid — a method taking `List<Number>` would reject a `List<Integer>` argument. **Wildcards** restore flexibility at the call site while preserving safety. The hard part is choosing **which** wildcard. That is what **PECS** answers. ## PECS spelled out **Producer Extends, Consumer Super.** - A parameter is a **producer** of T if your method *reads* T values out of it. Use `<? extends T>`. You can read T (covariance), but you can't safely write (you don't know the exact subtype). - A parameter is a **consumer** of T if your method *writes* T values into it. Use `<? super T>`. You can write T and its subtypes (contravariance), but reads come back only as Object. If a parameter is both read and written as T, use an exact type `T` (no wildcard). ## Worked example: a copy method ```java public static <T> void copy(List<? super T> dest, List<? extends T> src) { for (int i = 0; i < src.size(); i++) { T element = src.get(i); // src PRODUCES T → extends dest.set(i, element); // dest CONSUMES T → super } } ``` - `src` is read from → producer → `List<? extends T>`. This lets `src` be a `List<Integer>` when T is Number. - `dest` is written to → consumer → `List<? super T>`. This lets `dest` be a `List<Number>` or `List<Object>` when T is Integer. Without these wildcards you could only copy `List<T>` into `List<T>` — far less useful. With them: ```java List<Integer> ints = List.of(1, 2, 3); List<Number> nums = new ArrayList<>(List.of(0, 0, 0)); copy(nums, ints); // T inferred as Integer (or Number); both wildcards satisfied ``` ## Why `<? super T>` is the *right* choice for a destination A destination only ever receives writes of T (or subtypes of T). Any list whose element type is a *supertype* of T can hold a T safely, because a T **is-a** that supertype. So `<? super T>` is exactly the set of valid destinations — no more, no less. Narrowing it to `List<T>` would needlessly reject valid `List<Number>`/`List<Object>` destinations. ## Real JDK signatures that follow PECS - `Collections.copy(List<? super T> dest, List<? extends T> src)` - `Collections.fill(List<? super T> list, T obj)` - `Collections.addAll(Collection<? super T> c, T... elements)` - `Stream.forEach(Consumer<? super T> action)` — a `Consumer<? super T>` consumes T. - `Comparator` factory methods take `Comparator<? super T>`. ## Caveat / good taste Don't add a wildcard to a *return type* — it forces wildcards onto every caller. And don't over-wildcard internal or single-use methods; PECS pays off mostly on **public, reusable** APIs where caller flexibility matters.
- In `Collections.copy(List<? super T> dest, List<? extends T> src)`, which argument is the producer and which is the consumer?`src` is the producer (you read T out of it → extends); `dest` is the consumer (you write T into it → super).
- Why shouldn't you use a wildcard on a method's return type?A wildcard in the return type leaks into the caller's code: the caller is forced to deal with a wildcard type (e.g. can only read as Object), making the API harder to use. Return concrete types instead.
saying these in an interview costs you the question
- Swapping the rule — using extends for a consumer or super for a producer.
- Putting a wildcard on the return type (forces wildcards on all callers).
- Claiming `<? super T>` lets you read T back (only Object).
- Adding wildcards everywhere, including private/internal methods, hurting readability.