Generics
In short: A way to write classes and methods so they can work with different data types, without writing a separate, almost identical version for every type.
In more detail: A generic list, for example, can be used with List<Number> or List<Text>, with the same class code behind it — the concrete type is fixed when using it. The big advantage over a list that simply accepts anything: errors from wrong types are already caught at compile time, instead of only causing a crash at runtime.
In Depth
Without generics, you’d face two bad alternatives: either write an almost identical, separate class for every data type (NumberList, TextList, PersonList, …) — massive code duplication — or build a single list that simply accepts “anything” (any arbitrary type), which, however, only makes type errors visible at runtime, when suddenly a piece of text shows up where a number was expected.
List<String> names = new ArrayList<>();
names.add("Anna");
names.add(42); // compiler error! 42 isn't a String - the error is caught IMMEDIATELY
List unchecked = new ArrayList(); // without generics: accepts anything
unchecked.add("Anna");
unchecked.add(42); // no error at compile time...
// ... crashes only later, when the code wrongly calls a String method on 42The addition in angle brackets (<String>, <Number>) is called a type parameter — it works conceptually similar to a normal parameter of a function, except that here it’s not a value but an entire data type that’s “passed in”. The compiler uses this information to check, on every use of the list, whether the inserted or read values actually match the specified type.
Generics aren’t only used for collections, but for any class or method whose logic works independently of the concrete data type:
class Box<T> {
private T content;
void setContent(T value) { content = value; }
T getContent() { return content; }
}
Box<Integer> numberBox = new Box<>();
Box<String> textBox = new Box<>();Here, T stands as a placeholder for “some concrete type, fixed when using it” — the same Box class code works for any content, with no need to write a separate box class for every possible content type. This principle — write code once, reusable for many types — is closely related to abstraction and is often combined with the classic interface concept, to additionally restrict WHICH types are even allowed as type parameters (e.g. only types that have a specific method).
See also: Classes, List, Type Casting