Unravel โบ Java concepts โบ Generics and functional
Generics
Generics put a type in angle brackets, as in List<String>, so the compiler checks what a container holds and you need no casts.
At a glance
A labelled box: a "Box of Apples" cannot accidentally receive a screwdriver, and anything you take out is known to be an apple.
- 1List<String> says every element is a StringMap<String, List<Order>> nests the idea: names mapped to lists of orders.
- 2Methods can have their own type parameter: <T> T first(List<T> list)The compiler infers T from the arguments.
- 3The diamond new ArrayList<>() lets the compiler fill in the type from the left sidevar lets it infer the variable type from the right side.
- Generics exist only at compile time (type erasure)
- Wildcards express flexibility: List<?
- The compiler checks the types, inserts casts where needed and erases the type arguments, which is why old code without generics still runs
public static <T extends Comparable<T>> T largest(List<T> items) { T best = items.get(0); for (T item : items) { if (item.compareTo(best) > 0) { best = item; } } return best;}Read the full explanation (about 1 min)
Generics put a type in angle brackets, as in List<String>, so the compiler checks what a container holds and you need no casts.
A mental model
A labelled box: a "Box of Apples" cannot accidentally receive a screwdriver, and anything you take out is known to be an apple.
How it works
List<String> says every element is a String. Map<String, List<Order>> nests the idea: names mapped to lists of orders.
Methods can have their own type parameter: <T> T first(List<T> list). The compiler infers T from the arguments.
The diamond new ArrayList<>() lets the compiler fill in the type from the left side. var lets it infer the variable type from the right side.
Going deeper
Generics exist only at compile time (type erasure). At runtime List<String> and List<Integer> are both just List, so you cannot write new T() or instanceof List<String>.
Wildcards express flexibility: List<? extends Number> can be read as numbers but not added to; List<? super Integer> can be added to. Rule of thumb: "producer extends, consumer super".
A List<Dog> is not a List<Animal>, even though a Dog is an Animal; otherwise you could add a Cat through the Animal view.
Under the hood
The compiler checks the types, inserts casts where needed and erases the type arguments, which is why old code without generics still runs. Bridge methods are generated to keep overriding working.
Common mistakes
- Raw types (
Listwithout type) that disable checks. - Assuming
List<Dog>is aList<Animal>. - Trying to create generic arrays or
new T().
How Unravel recognises it
When you paste code, Unravel looks for these signs of generics. Spotting them yourself is a good habit when you read unfamiliar code:
- Language constructs:
generics
Part of a learning path
- Modern Java: lambdas and streams ยท previous: Method references ยท next: Collections: List, Set, Map
Related concepts
Builds on this
Frequently asked questions
What is Generics?
Generics put a type in angle brackets, as in List<String>, so the compiler checks what a container holds and you need no casts.
What are the most common mistakes with Generics?
Raw types (List without type) that disable checks. Assuming List<Dog> is a List<Animal>. Trying to create generic arrays or new T().
How can I see Generics in real code?
Paste your own Java into Unravel and it will point out where generics appears, explain how it works at the detail level you choose, and draw the flow of the code around it.