Quiz
Warm-up from lesson 7-1: what does the <String> in ArrayList<String> buy you?
Type parameters
Before Java 5, collections held plain Objects: you could put a String into a list of what you thought were Integers, and nothing complained until some distant line cast it back and crashed at runtime — in production, far from the actual mistake. Generics were added to move that entire class of bug to compile time, and they are why ArrayList<String> can promise what it holds. Here is the mechanism from the inside.
Suppose you write a Box class that holds one item. A StringBox, an IntBox, a DogBox... copies everywhere. Generics let you write it once with a placeholder type:
class Box<T> { private T item; void put(T item) { this.item = item; } T get() { return item; } }
T is a type parameter, a stand-in filled at use time: Box<String> makes every T mean String, Box<Integer> makes it Integer. This is exactly how ArrayList<E> and HashMap<K, V> are written in the standard library. The compiler enforces each choice: a Box<String> will not accept an Integer.
Code exercise · java
Run this. One Box class serves two element types. Try adding stringBox.put(42) to see the compiler protect you, then remove it.
Generic methods
A single method can be generic too. Declare the parameter before the return type:
static <T> T firstOf(ArrayList<T> list) { return list.get(0); }
Call it normally: firstOf(names) where names is an ArrayList<String> returns a String. Java infers T from the argument.
Conventions: T for a general type, E for a collection element, K/V for key and value. And a limitation you already met in lesson 7-1 applies here: type arguments must be object types, so Box<int> is invalid, use Box<Integer>.
Quiz
stringBox is a Box<String>. What happens on stringBox.put(42)?
Code exercise · java
Your turn. Write a generic class Pair<A, B> holding two fields, with a constructor and a toString returning `(<first>, <second>)`. Print a Pair of "age" and 30, then a Pair of 1 and 2.