Java Generics
Generics let you write classes and methods which work with many types, and still keep the type safe. You already use them in List<String> and Map<String, Integer>. The type in the angle brackets is a type parameter.
Why generics?
Without generics, a list holds Object, and you must cast. Mistakes show only when the program runs:
import java.util.ArrayList;
import java.util.List;
public class Raw {
public static void main(String[] args) {
List names = new ArrayList(); // raw type, no generics
names.add("Riya");
names.add(42); // no error here
String first = (String) names.get(1);
}
}
Raw.java:7: warning: [unchecked] unchecked call to add(E) as a member of the raw type List
names.add("Riya");
^
where E is a type-variable:
E extends Object declared in interface List
Raw.java:8: warning: [unchecked] unchecked call to add(E) as a member of the raw type List
names.add(42); // no error here
^
where E is a type-variable:
E extends Object declared in interface List
2 warnings
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:9)
With generics the compiler stops the mistake early:
import java.util.ArrayList;
import java.util.List;
public class Typed {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Riya");
names.add(42);
}
}
Typed.java:8: error: no suitable method found for add(int)
names.add(42);
^
method List.add(String) is not applicable
(argument mismatch; int cannot be converted to String)
method List.add(int,String) is not applicable
(actual and formal argument lists differ in length)
1 error
error: compilation failed
A generic class
class Box<T> {
private T value;
Box(T value) {
this.value = value;
}
T get() {
return value;
}
}
public class Main {
public static void main(String[] args) {
Box<String> a = new Box<>("Java");
Box<Integer> b = new Box<>(25);
String s = a.get(); // no cast needed
int n = b.get();
System.out.println(s + " " + n);
}
}
Java 25
A generic method
import java.util.Arrays;
public class Method {
static <T> void printAll(T[] items) {
for (T item : items) {
System.out.print(item + " ");
}
System.out.println();
}
static <T> T firstOf(java.util.List<T> list) {
return list.get(0);
}
public static void main(String[] args) {
printAll(new Integer[]{1, 2, 3});
printAll(new String[]{"a", "b"});
System.out.println(firstOf(Arrays.asList("x", "y")));
}
}
1 2 3
a b
x
Bounded types
Use extends to limit the type. T extends Comparable<T> means “T must be comparable”, so we can use compareTo:
import java.util.List;
public class Bound {
static <T extends Comparable<T>> T max(List<T> list) {
T best = list.get(0);
for (T item : list) {
if (item.compareTo(best) > 0) {
best = item;
}
}
return best;
}
public static void main(String[] args) {
System.out.println(max(List.of(3, 9, 4)));
System.out.println(max(List.of("pear", "apple", "zebra")));
System.out.println(max(List.of(2.5, 1.5)));
}
}
9
zebra
2.5
Wildcards
? means “any type”. ? extends Number accepts a list of Number or any subclass:
import java.util.List;
public class Wild {
static double sum(List<? extends Number> numbers) {
double total = 0;
for (Number n : numbers) {
total += n.doubleValue();
}
return total;
}
public static void main(String[] args) {
System.out.println(sum(List.of(1, 2, 3)));
System.out.println(sum(List.of(1.5, 2.5)));
}
}
6.0
4.0
Facts
- Generics work only with objects, not primitives:
List<Integer>, notList<int>. - Type information is removed after compile (type erasure), so you can not do
new T()orT.class. - Common names:
T(type),E(element),KandV(key and value).
| Exercises & Assignments |
|---|
| No Content Found. |
| Interview Questions & Answers |
|---|
| No Content Found. |