Generics in Java
Generics replace runtime failure with compile time guarantees. Before Java 5, casts hid defects until production execution.
Do Not Use Raw Types
Raw types disable generic checking.
Bad:
List list = new ArrayList();
list.add("Hello");
list.add(123);
String s = (String) list.get(1); // ClassCastException
Generic form:
List<String> list = new ArrayList<>();
list.add("Hello");
// list.add(123); // compile error
Benefits:
Raw types exist for backward compatibility only.
Example
Trade caches storing Trade objects inside raw List allow accidental insertion of String audit messages. Pricing logic casts blindly and fails during valuation windows. Generic collections stop this defect before deployment.
Prefer Lists to Arrays
Arrays and generics differ in two fundamental ways.
1) Covariance vs Invariance
Arrays are covariant.
Object[] objects = new Long[1];
objects[0] = "FAIL"; // ArrayStoreException
Compiles, fails at runtime.
Generics are invariant.
List<Object> objects = new ArrayList<Long>(); // compile error
Fails at compile time, not in production.
2) Reification vs Erasure
Arrays keep element type at runtime. Java checks every store.
Generics erase type info at runtime. List<String> and List<Integer> both appear as List.
Mixing both models leads to unsafe constructs.
Bad idea:
List<String>[] table = new List<String>[10];
Correct approach:
List<List<String>> table = new ArrayList<>();
Example
Portfolio matrices stored as arrays accept wrong instrument types silently until valuation time. Using List<List<Position>> moves detection to compilation, not market open.
Use Bounded Wildcards for Flexible APIs
Generic APIs become rigid without wildcards.
Problem:
public void pushAll(Iterable<E> src)
Usage:
Stack<Number> stack = new Stack<>();
Iterable<Integer> ints = ...;
stack.pushAll(ints); // compile error
Iterable<Integer> is not Iterable<Number>.
Fix:
public void pushAll(Iterable<? extends E> src)
Now subtypes work.
PECS Rule
Producer Extends, Consumer Super.
This keeps APIs open without sacrificing safety.
Example
Order routers accept batches of EquityOrder into a Collection<Order>. Without wildcards, teams duplicate pipelines. With PECS, routing logic supports every subtype cleanly.
Design Rules
Takeaway
Generics enforce contracts at compile time. They shift failure left, away from production windows.