Skip to main content

Generics & Bounded Types

beginner20 min readLesson 46 of 180

Type parameters, your own Box<T>, generic methods, and T extends Comparable<T>.

Generic type parameters (<T>) are how Java collections stay type-safe โ€” and how you write your own reusable containers.

Using them, you already do: List<String>, Map<String, Integer>. The compiler stops list.add(42) on a List<String> at compile time, and eliminates casts on the way out. Before generics (Java 4 and earlier), everything was Object and every read was a risky downcast โ€” generics moved those crashes from runtime to the compiler.

Writing them is one angle-bracket declaration:

class Box<T> {                       // T: a type filled in later
    private T value;

    public void put(T v) { value = v; }
    public T get() { return value; }
}

Box<String> words = new Box<>();
words.put("hi");                     // compile-checked
String s = words.get();              // no cast

Generic methods declare their own type parameter before the return type:

static <T> T firstOrNull(List<T> list) {
    return list.isEmpty() ? null : list.get(0);
}

Call it with List<String> and T becomes String; with List<Integer> and T becomes Integer โ€” one method, every element type, no duplication.

Bounded types constrain T when behavior needs a guarantee:

static <T extends Comparable<T>> T maxOf(List<T> items) {
    T best = items.get(0);
    for (T item : items) {
        if (item.compareTo(best) > 0) best = item;
    }
    return best;
}

T extends Comparable<T> reads "any type that knows how to compare itself" โ€” inside, compareTo is legal. Bounds are the beginner-safe half of generics; wildcards (? extends, ? super) and variance belong to Intermediate โ€” this course deliberately stops at bounds.

Next: exceptions.

Now practice

Practice: Collections at WorkA stock ledger of maps, word counting, and a hand-rolled generic Box with a bounded max.3 challenges ยท ยท ~50 min