Java Generics Introduction
In this page:
// generic type parameter T
class ClassName<T> { }
List<Type> list = new ArrayList<>();
What are Generics?
Generics are a powerful feature in Java that let you write classes, interfaces, and methods where the data type is passed in as a parameter instead of hard-coded. This gives you strong, compile-time type safety, catching type mismatches long before your code ever runs.
Example: What are Generics?
// Define the class Main
public class Main {
// Define the class Box
static class Box<T> {
private T value;
Box(T value) { this.value = value; }
T get() { return value; }
}
// Program entry point: the JVM starts running here
public static void main(String[] args) {
// Create a new Box object and store it in box
Box<String> box = new Box<>("Hello");
// Print a line to the console
System.out.println(box.get());
}
}
Login to try C/C++/Java/PHP code in the editor
Type Safety Benefits
Before Generics, you could store any object in a collection like ArrayList, which often caused runtime ClassCastExceptions when you pulled an item out expecting one type but got another. Generics solve this by having the compiler catch that mismatch at compile-time instead, well before the code ships.
Example: Type Safety Benefits
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Apple");
// list.add(42); // would not compile -- caught by the compiler, not at runtime
String item = list.get(0);
System.out.println(item);
}
}
Login to try C/C++/Java/PHP code in the editor
Eliminating Manual Casting
Without Generics, retrieving elements from a collection required explicit, manual type casting on every access, which was verbose and error-prone. Generics eliminate this overhead entirely, letting the compiler insert and verify the cast automatically behind the scenes.
Example: Eliminating Manual Casting
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Riya");
String name = names.get(0); // no manual cast needed, compiler inserts it
System.out.println(name);
}
}
Login to try C/C++/Java/PHP code in the editor
Standard Library Generics
The standard Java Collections Framework, including List, Set, and Map, uses Generics heavily throughout its API. This ensures the data flowing through your application stays structured and type-safe from the moment it's stored to the moment it's read back out.
Example: Standard Library Generics
// Import java.util.* so it can be used by its short name
import java.util.*;
// Define the class Main
public class Main {
// Program entry point: the JVM starts running here
public static void main(String[] args) {
// Create a new ArrayList object and store it in list
List<String> list = new ArrayList<>();
// Create a new HashSet object and store it in set
Set<Integer> set = new HashSet<>();
Map<String, Integer> map = new HashMap<>();
list.add("data");
set.add(1);
map.put("key", 100);
// Print a line to the console
System.out.println(list.get(0) + " " + set.contains(1) + " " + map.get("key"));
}
}
Login to try C/C++/Java/PHP code in the editor
Generic Naming Conventions
By convention, type parameters are named using single uppercase letters so they're instantly recognizable as placeholders rather than real classes. Common naming parameters include T (Type), E (Element), K (Key), and V (Value), and following this convention makes unfamiliar generic code much easier to read.
Example: Generic Naming Conventions
// Define the class Main
public class Main {
// Define the class Pair
static class Pair<K, V> {
K key; V value;
Pair(K key, V value) { this.key = key; this.value = value; }
}
static <T> void printItem(T item) {
// Print a line to the console
System.out.println(item);
}
// Program entry point: the JVM starts running here
public static void main(String[] args) {
// Create a new Pair object and store it in p
Pair<String, Integer> p = new Pair<>("age", 25);
printItem(p.key + "=" + p.value);
}
}
Login to try C/C++/Java/PHP code in the editor
- Using primitive types as type arguments, like
Box<int>, which does not compile because generics need reference types; useBox<Integer>. - Using a raw type such as
Box b = new Box(5);, which loses type safety and brings back the casting andClassCastExceptionproblems generics were meant to prevent. - Assuming
List<String>can be assigned toList<Object>because String is an Object, which is a compile error since generics are not covariant.
Chapter Quiz — Complete all 4 topics to unlock
0/4 topics done
Complete these topics first: