Skip to main content

Wildcards and Type Tokens

Source: Effective Java, 3rd Edition — Chapter 5 by Joshua Bloch (Items 30–33)

This lesson finishes Chapter 5: generic methods, bounded wildcards (PECS), varargs with generics, and typesafe heterogeneous containers keyed by Class tokens.

Item 30: Favor generic methods​

Methods can be generic too. Type parameters go between modifiers and the return type:

public static <E> Set<E> union(Set<E> s1, Set<E> s2) { ... }

Raw Set union(Set s1, Set s2) compiles with unchecked warnings and erases safety. A parameterized version compiles cleanly and needs no client casts.

Generic singleton factory: one stateless object serves all type parameterizations because of erasure — e.g. Function.identity(). A private UnaryOperator<Object> plus a generic factory method with narrow @SuppressWarnings("unchecked") is the pattern.

Recursive type bound: mutual comparability — elements comparable to each other:

public static <E extends Comparable<E>> E max(Collection<E> c)

Read <E extends Comparable<E>> as “E that can be compared to itself.”

Item 31: Use bounded wildcards to increase API flexibility​

Generics are invariant: Stack<Number> cannot accept Iterable<Integer> even though Integer extends Number.

PECS — producer-extends, consumer-super:

RoleWildcardExample
Producer (source of T)<? extends T>pushAll(Iterable<? extends E> src)
Consumer (sink for T)<? super T>popAll(Collection<? super E> dst)
Both producer and consumerexact typeno wildcard

Do not use wildcards on return types — that forces clients to use wildcards too.

Flexible union:

public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2)

Revised max:

public static <T extends Comparable<? super T>> T max(List<? extends T> list)

Comparable and Comparator are consumers — prefer Comparable<? super T>.

Wildcard capture: public swap(List<?> list, int i, int j) delegates to private <E> void swapHelper(List<E> list, ...).

If a type parameter appears once in a public method, prefer a wildcard (List<?> over <E> List<E>) unless you need capture.

Quiz

PECS and wildcards

1 / 2

Stack<Number>.pushAll(Iterable<Integer> ints)

Pick an answer to see if you are right.

Item 32: Combine generics and varargs judiciously​

Varargs builds an array at each call — a leaky abstraction. Generic varargs parameters are non-reifiable, so the compiler warns about heap pollution:

static void dangerous(List<String>... stringLists) { ... } // warning

Storing into the varargs array or returning it (T[] toArray(T... args) { return args; }) breaks type safety — pickTwo returning Object[] assigned to String[] fails at runtime with a hidden cast.

Safe varargs when the array is only a pass-through (read elements, don’t store alien types, don’t escape the array). Annotate with @SafeVarargs on static, final, or (Java 9+) private methods — never on overridable methods unless every override is safe.

Library examples: Arrays.asList, Collections.addAll, EnumSet.of, List.of.

Alternative: take List<T> instead of T... — verbose but provably safe (flatten(List<List<? extends T>> lists)).

Quiz

Generics and varargs

1 / 2

static <T> T[] toArray(T... args) { return args; }

Pick an answer to see if you are right.

Item 33: Consider typesafe heterogeneous containers​

Set<E> and Map<K,V> fix one or two type parameters per container. Sometimes you need many types in one bag — parameterize the key, not the whole container.

Type token: Class<T> — String.class has type Class<String>. Favorites API:

public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);

Backing store: Map<Class<?>, Object>. Values are stored as Object; type.cast(obj) on read restores the link — no unchecked cast to T.

Runtime safety on put: favorites.put(type, type.cast(instance)). Cannot store favorites keyed by non-reifiable types like List<String>.class (illegal).

Bounded type tokens: Class<T extends Annotation> for getAnnotation. Class.asSubclass(Annotation.class) safely narrows an unbounded Class<?>.

Items 30–33 map​

ItemMove
30Generic methods; recursive Comparable<E> bounds
31PECS: ? extends producers, ? super consumers
32Varargs = arrays; @SafeVarargs only when transmit-only; prefer List
33Heterogeneous container: Class<T> keys + type.cast

Chapter 5 complete. Next: Enums (Chapter 6, Items 34–37).