List, Map, Set & Generics
The Java Collections Framework — the type-safe, resizable data structures you'll reach for in nearly every program.
Arrays
Arrays are fixed-size and hold a single type. Their length is set at creation and never changes — for a resizable list, you use ArrayList instead.
int[] nums = {5, 2, 8, 1}; nums.length; // 4 — a field, not a method nums[0]; // 5 String[] names = new String[3]; // [null, null, null] names[0] = "Alice"; // Arrays utility class Arrays.sort(nums); // [1, 2, 5, 8] — sorts in place Arrays.toString(nums); // "[1, 2, 5, 8]" // 2D array int[][] grid = {{1, 2}, {3, 4}}; grid[1][0]; // 3
List & ArrayList
List is the interface; ArrayList is the everyday implementation — a resizable array. Program to the interface (List<String> x = new ArrayList<>()) so you can swap the implementation later.
List<String> names = new ArrayList<>(); names.add("Alice"); names.add("Bob"); names.get(0); // "Alice" names.size(); // 2 names.contains("Bob"); // true names.remove("Alice"); // removes by value // iterate for (String n : names) System.out.println(n); // immutable list literal (Java 9+) List<Integer> fixed = List.of(1, 2, 3); // cannot be modified
List<int> is illegal. Use the wrapper type: List<Integer>. Java autoboxes the primitives for you.Map & Set
HashMap stores key-value pairs with O(1) average lookup; HashSet stores unique values only. Both are unordered — use LinkedHashMap/TreeMap when order matters.
Map<String, Integer> scores = new HashMap<>(); scores.put("alice", 95); scores.put("bob", 88); scores.get("alice"); // 95 scores.getOrDefault("x", 0); // 0 — no crash on missing key scores.containsKey("bob"); // true // count occurrences — the classic merge idiom scores.merge("alice", 1, Integer::sum); Set<Integer> unique = new HashSet<>(); unique.add(1); unique.add(1); unique.add(2); unique.size(); // 2 — duplicate ignored
Generics
Generics let a class or method work with any type while keeping full compile-time type safety. The <String> in List<String> means the compiler rejects anything but Strings — no casts, no runtime surprises.
// Generic method — <T> means "works for any type T" static <T> T firstOf(List<T> list) { return list.get(0); } String s = firstOf(List.of("a", "b")); // T inferred as String // Generic class — a type-safe box class Box<T> { private T value; void set(T v) { value = v; } T get() { return value; } } Box<Integer> box = new Box<>(); box.set(42); int n = box.get(); // no cast needed — compiler knows it's Integer
Object and you cast on every read — one wrong cast blew up at runtime. Generics move that check to compile time, so the whole class of ClassCastException bugs disappears.