Generics in Java
Imagine a cupboard labeled "Spices". Anyone can still put a hammer in it, and you only find out when you reach for the turmeric. Before Java 5, collections worked like that cupboard: a List accepted any object, and mistakes surfaced only when the program crashed. Generics add a type to the label, List<String>, and the compiler refuses the hammer. A bug that used to appear at runtime, in front of a user, now appears while you're still typing.
The Bug Generics Prevent
Without a type, the list happily accepts a number among the names:
import java.util.ArrayList;
import java.util.List;
public class Raw {
public static void main(String[] args) {
List names = new ArrayList();
names.add("Navika");
names.add(42);
for (Object o : names) {
String s = (String) o;
System.out.println(s.toUpperCase());
}
}
}NAVIKA
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
at Raw.main(Raw.java:10)The mistake (adding 42) is on line 8, but the crash happens on line 10, later, when the value is used. In a real program, those two lines could be in different files written months apart.
With a type parameter (List<String> names = new ArrayList<>(); in the same file), the same mistake doesn't compile:
Typed.java:8: error: incompatible types: int cannot be converted to String
names.add(42);
^Using a Generic Type
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Safe {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Navika");
names.add("Srihitha");
String first = names.get(0);
System.out.println(first.toUpperCase());
Map<String, Integer> marks = new HashMap<>();
marks.put("Advitha", 93);
int score = marks.get("Advitha");
System.out.println(score + 5);
}
}NAVIKA
98How it works
List<String>reads "a list of strings".Stringis the type argument filling the list's type parameter.names.get(0)returns aStringdirectly: no cast is needed.Map<String, Integer>has two type parameters: the key type and the value type.new ArrayList<>()uses the diamond<>: the compiler works outStringfrom the left side (see "Diamond Operator in Java").
What Generics Give You
| Benefit | Without generics | With generics |
|---|---|---|
| Type safety | Wrong types are found at runtime, as ClassCastException | Wrong types are compile errors |
| No casts | (String) list.get(0) everywhere | list.get(0) is already a String |
| Reusable code | Write StringList, IntegerList... | Write List<T> once, use it for any type |
| Self-documenting | List orders: of what? | List<Order> orders says it |
Naming Type Parameters
By convention, type parameters are single capital letters, so they're never confused with class names:
| Letter | Usually means | Example |
|---|---|---|
T | Type | Box<T> |
E | Element (in collections) | List<E> |
K, V | Key, Value | Map<K, V> |
N | Number | Calculator<N extends Number> |
R | Return type | Function<T, R> |
Common Mistakes
Using raw types like List without <...>. You lose all checking (see "Raw Types in Java").
List<int>. Use the wrapper class: List<Integer>.
Casting the results of a generic collection. If you need a cast, the type parameter is probably wrong.
Interview Corner
What are generics and why are they used?
Generics, added in Java 5, let classes, interfaces and methods take type parameters, as in List<String> or Map<K, V>. They provide compile-time type safety, catching wrong-type insertions as compile errors instead of runtime ClassCastExceptions, remove the need for explicit casts, and let one implementation be reused for many types.
Can you use primitive types as generic type arguments?
No. Type arguments must be reference types, so List<int> is a compile error. Use wrapper classes such as List<Integer>; autoboxing converts between primitives and wrappers automatically.
Practice
- Easy: Create a
List<Double>of three prices, and add them up without any casts. - Harder: Create a
Map<String, List<Integer>>that holds each student's marks for Navika, Srihitha and Advitha, and print each student's highest mark.
Key Takeaways
Was this tutorial helpful?