Type Parameters in Java Generics β€” <code>&lt;T&gt;</code>

A type parameter is a placeholder for a concrete type that the compiler fills in at each use site. <T> in List<T> is what makes List<String> and List<Integer> different types. Type parameters exist on classes, interfaces, and methods.

Generic class

public class Box<T> {
    private final T value;
    public Box(T value) { this.value = value; }
    public T get() { return value; }
}

Box<String> s = new Box<>("hello");     // diamond infers <String>
Box<Integer> i = new Box<>(42);

Generic method

public static <T> List<T> repeat(T value, int n) {
    List<T> out = new ArrayList<>();
    for (int k = 0; k < n; k++) out.add(value);
    return out;
}

var words = repeat("hi", 3);              // List<String> β€” inferred
var nums  = Utils.<Integer>repeat(0, 5);  // explicit type witness β€” rarely needed

The <T> before the return type declares the type parameter. It's local to the method β€” not tied to the enclosing class's type parameters.

Multiple type parameters

public record Pair<A, B>(A first, B second) {}

public static <K, V> Map<V, K> invert(Map<K, V> in) {
    var out = new HashMap<V, K>();
    in.forEach((k, v) -> out.put(v, k));
    return out;
}

Naming conventions

LetterTypical meaning
TType (single)
EElement of a collection
K, VKey, Value (for maps)
RReturn type
NNumber

For domain-specific generics, spell it out: <Event>, <Payload>. No one-letter law.

Type inference rules (simplified)

  • Diamond (<>): inferred from the left-hand side.
  • Method call: inferred from the argument types and the expected return type (target typing).
  • var: inferred from the initialiser.

Bounded type parameters (preview)

public static <T extends Comparable<T>> T max(List<T> xs) { ... }

See the bounded types page for the full treatment.

Common mistakes

  • Declaring <T> twice β€” once on the class and once on a method in the class with the same name. The method's T shadows the class's.
  • Using a raw type β€” List list = new ArrayList(). Always parameterise.
  • Over-genericising β€” if every type is <T>, the abstraction no longer says anything about the domain.

Related

Pillar: Java generics. See also wildcards, bounded types.