Generics and Optional
Parameterize APIs for type safety, use bounds and wildcards correctly, and represent an absent return value explicitly.
Why it matters
Start from the concept, not the syntax
Meet a concrete situation where this idea earns its place, then state the boundary it guards.
Generics let one piece of code work on many types while the compiler checks every use. A single Box<T> or List<String> replaces copy-pasted versions and pushes ClassCastException from runtime back to compile time, where it belongs.
By the end of this chapter
Raw types and wrong wildcards push ClassCastException back to runtime and defeat the safety generics exist to provide.
- Parameterized types
- Bounded parameters
- PECS wildcards
Mechanism
How Java expresses the concept
Walk the actual types, rules, and runtime behavior involved—the same behavior described in the Java Language Specification.
The mental model
A generic class or method parameterizes a type: `Box<T>` holds a `T`, and `List<String>` promises only strings. This moves a whole class of `ClassCastException` errors from runtime to compile time.
Type parameters can be bounded: `<T extends Number>` accepts `Number` and its subclasses. Wildcards express flexibility: `? extends T` for reading (producer), `? super T` for writing (consumer). This is the PECS rule: Producer Extends, Consumer Super.
Generics are erased at runtime: `List<String>` and `List<Integer>` are the same class at runtime, so you cannot use `T` in `new T[...]` or `instanceof`. The diamond operator `<>` lets the compiler infer the type arguments so you avoid repeating them.
`Optional<T>` is primarily a return type for a method that may have no result. It should not itself be `null`, and it is not a replacement for every nullable field or parameter.
Bounded types and wildcards are easy to overuse. Start with a single `<T>`; add bounds only when a method truly needs to call a supertype method or accept a family of subtypes.
Concept map
Inspect the building blocks as a whole
Use the map as a structural reference; it shows the pieces and their relationships, not an execution sequence.
Core Java
Generics and type safety
Generics let one class or method work on many types while keeping compile-time type checks and avoiding casts.
- 01Parameterized types
- 02Compile-time safety
- 03Bounded type parameters
- 04PECS wildcards
- 05Type erasure
- 06Diamond operator
- 07Optional return values
Implementation
Encode the smallest runnable example
Write and run the code, then observe the behavior you just predicted with a real Java program.
Runnable snippet path
Predict, run, and change each example
A generic box
One class serves any type while keeping the type checked at compile time.
public class Box<T> {
private T value;
void set(T value) { this.value = value; }
T get() { return value; }
}
class Use {
static void demo() {
Box<String> b = new Box<>();
b.set("hi");
String s = b.get(); // no cast
}
}Remember
Use the diamond <> so the compiler infers the type argument for you.
Change one input, predict the result, then compile or test it before continuing.
PECS wildcard
A consumer that adds Ts uses super; a producer that reads uses extends.
import java.util.*;
class Copy {
static <T> void copy(List<? super T> dest, List<? extends T> src) {
dest.addAll(src);
}
}Remember
Producer Extends, Consumer Super: it prevents adding the wrong type.
Change one input, predict the result, then compile or test it before continuing.
Watch out
Break it on purpose, then repair the right layer
Predict the symptom before running the failure case, and close with the completion checklist.
Deliberate failure
Break
Use a raw List and cast elements on the way out
Observe
A ClassCastException is thrown far from where the bad value entered
Repair
Keep the type parameter, use the diamond operator, and apply PECS when a method both reads and writes
Why it matters
Keep the type parameter, use the diamond operator, and apply PECS when a method both reads and writes
Completion checklist
- Use a type parameter for reusable code
- Bound a parameter when a method needs supertype behavior
- Apply extends and super wildcards correctly
Go deeper
Official references
The primary sources behind this chapter. Every claim above stays consistent with them.