skip to content

When would you choose List<?> for a method parameter instead of a generic type parameter like <T> List<T>?

level: seniorimportance: should knowfreq 48%

answer

  1. Wildcard: type never named in the body
  2. Type parameter: type reused across signature/return
  3. One-occurrence rule -> use a wildcard
  4. swap needs capture helper (private <T>)
  5. Unbounded ? only when Object ops suffice

basics

~20 s

Use List<?> when the method only cares that it has a list and never needs to name the element type - for example to check its size or print it. Use a type parameter <T> when the element type must appear in more than one place, like returning an element of that same type.

solid answer

~50 s

Choose the unbounded wildcard List<?> when the element type is irrelevant to the method - the body only uses operations that don't depend on it, like size(), isEmpty(), clear(), or reading elements as Object. It is simpler and reads better than introducing an unused type variable. Choose a generic method <T>(List<T> ...) when the type must be referred to more than once or related across parameters and the return type - e.g. T first(List<T> l) returns the same T, or swap(List<T> l, int i, int j) needs to take an element out and put it back. A useful refactoring trick: if a type parameter appears exactly once in a signature and nowhere else needs naming, replace it with a wildcard. Wildcards make the API cleaner for callers; type parameters are needed when you must capture and reuse the type.

go deeper

for a junior

Knows List<?> is for methods that don't care about the element type, like printing or sizing.

for a middle

Can give examples of each and knows the return type or shared use forces a type parameter.

for a senior

Applies the one-occurrence rule of thumb and knows the wildcard-capture helper pattern for cases like swap.

for a principal

Sets API-design conventions: minimal wildcard surface for callers, type parameters only where the type is genuinely reused, and bounded wildcards where Object is insufficient.

## Two tools for 'a list of unspecified element type' Java gives you two ways to write a method that works over lists regardless of element type: 1. **Unbounded wildcard:** `void f(List<?> list)` 2. **Generic method (type parameter):** `<T> void f(List<T> list)` They look similar but serve different needs. ## Use the wildcard when the type is never named If the method body never needs to *name* the element type - it only calls operations that don't depend on it - prefer the wildcard. Examples: ``` int size(List<?> l) { return l.size(); } boolean empty(List<?> l) { return l.isEmpty(); } void clear(List<?> l) { l.clear(); } // removing doesn't need the type void printAll(List<?> l) { for (Object o : l) System.out.println(o); } ``` Introducing `<T>` here would add a type variable that is used exactly once and carries no information - noise. ## Use a type parameter when the type must be reused If the element type appears in **more than one place** - across parameters, or in the return type, or you must take a value out and put one back - you need a named type variable so the compiler can tie those occurrences together: ``` <T> T first(List<T> l) { return l.get(0); } // return type = element type <T> void copy(List<T> dst, List<T> src) { ... } // two params share T ``` A `swap` is the classic case: with `List<?>` you can read an element only as `Object` and you cannot put it back, so you cannot implement swap directly. The standard fix is the **wildcard capture helper**: a public `void swap(List<?> l, int i, int j)` that delegates to a private generic `<T> void swapHelper(List<T> l, int i, int j)`, which captures the wildcard into a real `T`. ## The one-occurrence rule of thumb (Effective Java) A practical guideline: *if a type parameter appears only once in a method signature, replace it with a wildcard.* The wildcard version is simpler for callers, who don't have to think about the type variable. Conversely, a type parameter that appears once and is otherwise unconstrained is usually a smell that a wildcard would be cleaner. ## Bounded vs unbounded This question is about the *unbounded* wildcard specifically. If the method needs to read elements as something more specific than `Object` (e.g. `Number`), use an *upper-bounded* wildcard `? extends Number` instead. Use the unbounded `?` only when `Object` operations suffice. ## Caller-side benefit Wildcards keep the API surface minimal: `List<?>` says exactly 'a list of anything, I won't depend on the type'. That is clearer documentation than `<T> ... List<T>` when `T` is never used meaningfully.

  • How do you implement swap when the public method takes List<?>?
    Delegate to a private generic helper: public void swap(List<?> l,int i,int j){ swapHelper(l,i,j);} private <T> void swapHelper(List<T> l,int i,int j){ T t=l.set(i,l.get(j)); l.set(j,t);} The helper captures the wildcard as a real T.
  • What is the rule of thumb for choosing between them?
    If a type parameter appears only once in the signature and isn't otherwise needed, replace it with a wildcard; if the type must be named more than once (e.g. shared params or the return type), keep the type parameter.

saying these in an interview costs you the question

  • Always reaching for <T> even when the type is used once - prefer the wildcard there
  • Claiming you can implement swap directly on List<?> - you need a capture helper
  • Using unbounded ? when you actually need ? extends SomeBound to call type-specific methods
  • Thinking wildcards and type parameters are interchangeable in all cases

context