MA-JAVA0 · Module 10
Collections preview, arrays of objects, and null
Topics: ArrayList · Arrays of objects · null · Null checks
Overview
Session 10 — Collections preview, arrays of objects, and null
You will contrast fixed T[] arrays with ArrayList<E>, store objects in arrays, and treat null as “no object here” — including why calling a method on a null reference crashes. This mirrors the syllabus topic arrays of objects and the null value.
Time: about 75 minutes.
Concepts
1. From fixed arrays to growable lists
int[] cannot change length. java.util.ArrayList<E> stores references in a resizable backing array, doubling capacity as needed—amortised near-constant-time append at the end.
Declare with concrete type parameter:
import java.util.ArrayList;
ArrayList<String> lines = new ArrayList<>();
lines.add("first");
lines.add("second");
Diamond operator new ArrayList<>() lets the compiler infer String from the left-hand side.
2. Generics headline
Generics (<String>) give compile-time checks: you cannot add(42) into ArrayList<String> without a compile error. At runtime, generics undergo type erasure—the JVM sees raw lists but the compiler already blocked mistakes.
Wildcards (? extends, ? super) are treated in session 18; session 17 deepens named type parameters and bounds on your own APIs.
3. Core list operations
add(E value)appends.size()counts elements (method, unlike array.length).get(int index)reads by index.set(int index, E value)replaces.remove(int index)orremove(Object o)—know which overload you call.
4. Iteration
Enhanced for works:
for (String line : lines) {
System.out.println(line);
}
Traditional indexed loop still valid when index matters.
5. Arrays of objects
An array whose element type is a class stores references, not the objects themselves:
Student[] group = new Student[3];
// group[0], group[1], group[2] are all null until assigned
group[0] = new Student("Ada");
group[1] = new Student("Lin");
// group[2] still null
Loop carefully — for-each still visits null slots:
for (Student s : group) {
if (s != null) {
System.out.println(s.name);
}
}
This is the usual “arrays of objects and the null value” topic after you have classes (Session 6).
6. Null discipline
null means no object. Calling a method on it throws NullPointerException.
ArrayList may also contain null entries if you add them. Decide policy:
- Reject nulls at insertion time.
- Filter nulls before processing (
Objects.requireNonNull). - Leave slots null in a fixed
Student[]until filled — then always check before use.
Optional (since Java 8) models “maybe absent” more explicitly—preview usage:
String firstOrNull(ArrayList<String> data) {
if (data.isEmpty()) {
return null;
}
return data.get(0);
}
Later courses show Optional chaining; here simply acknowledge null as a deliberate signal.
7. Converting to arrays
lines.toArray(new String[0]) yields a String[] snapshot—useful for legacy APIs.
8. Pitfalls
- Autoboxing with
ArrayList<int>is illegal—useIntegerorIntStreampatterns later. - Modifying a list while iterating with enhanced-for can throw
ConcurrentModificationException—use iterator remove or collect changes first.
Examples
Example A — arrays of objects and null slots
public class Cohort {
static class Student {
String name;
Student(String name) {
this.name = name;
}
}
public static void main(String[] args) {
Student[] group = new Student[3];
group[0] = new Student("Ada");
group[1] = new Student("Lin");
// group[2] remains null
for (int i = 0; i < group.length; i++) {
if (group[i] == null) {
System.out.println("seat " + i + " empty");
} else {
System.out.println("seat " + i + ": " + group[i].name);
}
}
}
}
After new Student[3], every slot is null until you assign. Calling group[2].name without a check crashes.
Example B — token log (ArrayList)
import java.util.ArrayList;
public class TokenLog {
public static void main(String[] args) {
ArrayList<String> tokens = new ArrayList<>();
tokens.add("alpha");
tokens.add("beta");
tokens.add("gamma");
System.out.println(tokens.size()); // 3
for (String t : tokens) {
System.out.println(t.toUpperCase());
}
tokens.remove(1); // removes beta
System.out.println(tokens); // calls AbstractCollection.toString
}
}
println on lists relies on toString implementations—handy for debugging.
Example C — guarding null inserts
public static void safeAdd(ArrayList<String> sink, String maybe) {
if (maybe == null) {
throw new IllegalArgumentException("null token rejected");
}
sink.add(maybe);
}
Fail fast at boundaries so downstream loops stay simple.
Example D — array of objects and for-each + toString
public class ProductRow {
public static void main(String[] args) {
Product[] products = new Product[3];
products[0] = new Product("Cereal", 5, 250.0);
products[1] = new Product("Milk", 8, 120.0);
products[2] = new Product("Bread", 3, 90.0);
for (Product p : products) {
System.out.println(p);
}
// 3a — empty the second product's stock (index 1); fields are private
products[1].setQuantity(0);
products[1].setInStock(false);
System.out.println("After emptying the second product:");
System.out.println(products[1]);
}
}
Expected output from the for-each loop (each line comes from toString()):
name: Cereal
quantity: 5
price: 250.0
inStock: false
name: Milk
quantity: 8
price: 120.0
inStock: false
name: Bread
quantity: 3
price: 90.0
inStock: false
After setQuantity(0) and setInStock(false) on products[1]:
name: Milk
quantity: 0
price: 120.0
inStock: false
products[1] is the second product (index 1). You cannot write products[1].price = 0 when price is private — use setQuantity and setInStock.
Practice check — collections preview, arrays of objects, and null
Multiple-choice check from the Matheion app lesson. Pick an answer for each question, then submit.
1.Why is `ArrayList<int> nums = new ArrayList<>();` illegal?
2.After `Student[] seats = new Student[2];` with no assignments, what is `seats[0]`?
3.Why does `System.out.println(seats[0].name);` crash right after `new Student[2]`?
4.After `list.add("a"); list.add("b"); list.remove(0);` on an `ArrayList<String>`, what is `get(0)`?
5.How does `ArrayList.size()` differ from `array.length`?