Chapter 8
Lists and maps
An array has a fixed size. But often you don't know in advance how many elements there will be: items in a shopping cart, songs in a playlist. Java comes with ready-made containers for this, the collections. The three most important are list, set and map. They all live in java.util and need an import.
ArrayList
An ArrayList is like an array that grows. The angle brackets say what goes in:
List<String> names = new ArrayList<>();
On the left is the general type List, on the right the concrete ArrayList. The empty brackets <> (the "diamond") take the type from the left.
add(x)appends,get(i)reads positioni(from 0),set(i, x)replacessize()is the count,isEmpty()checks for emptyremove(i)removes positioni, everything after it moves upcontains(x)searches for an element
Only classes go in angle brackets. For numbers you write Integer instead of int and Double instead of double. Java converts automatically when adding and reading. Unlike an array, you can print a list directly. List.of("a", "b") quickly creates a fixed list that can't be changed afterwards.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Ada");
names.add("Bob");
names.add("Cleo");
System.out.println(names);
System.out.println("Size: " + names.size());
System.out.println("Index 1: " + names.get(1));
names.remove(0);
names.add("Dan");
System.out.println(names);
System.out.println(names.contains("Ada"));
List<Integer> squares = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
squares.add(i * i);
}
int sum = 0;
for (int n : squares) {
sum += n;
}
System.out.println(squares + " sum " + sum);
}
}Set: every element only once
A set contains each element at most once. add returns false if the element is already in it and leaves the set unchanged. Use it to remove duplicates or count distinct values.
HashSet: fast, but without a fixed orderLinkedHashSet: keeps the order in which the elements were added
A set has no get(i). If you need a list again, pass the set to the constructor: new ArrayList<>(set).
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
List<String> signUps = List.of("Mia", "Leo", "Mia", "Ana", "Leo");
Set<String> guests = new LinkedHashSet<>();
for (String name : signUps) {
boolean added = guests.add(name);
if (!added) {
System.out.println(name + " is already on the list");
}
}
System.out.println(guests);
System.out.println(guests.size() + " guests");
System.out.println(guests.contains("Ana"));
List<String> list = new ArrayList<>(guests);
System.out.println("Last: " + list.get(list.size() - 1));
}
}HashMap: key and value
A map stores pairs of key and value, such as name → phone number. Map<String, String> names both types.
put(key, value)stores; if the key already exists, the old value is replacedget(key)returns the value, ornullif the key is missinggetOrDefault(key, fallback)returns the fallback insteadcontainsKey(key),size(),keySet()for all keys
To count, take the previous count (or 0) and store it plus one, as in the example. Values can be lists themselves: Map<String, List<Integer>> stores a list of grades for each name.
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, String> phone = new HashMap<>();
phone.put("Ada", "0151 123");
phone.put("Bob", "0160 456");
phone.put("Ada", "0170 789");
System.out.println(phone.get("Ada"));
System.out.println(phone.get("Eve"));
System.out.println(phone.getOrDefault("Eve", "unknown"));
System.out.println(phone.containsKey("Bob"));
System.out.println(phone.size() + " entries");
String text = "the cat and the hat and the bat";
Map<String, Integer> counts = new HashMap<>();
for (String word : text.split(" ")) {
counts.put(word, counts.getOrDefault(word, 0) + 1);
}
System.out.println("the: " + counts.get("the"));
System.out.println("and: " + counts.get("and"));
System.out.println("cat: " + counts.get("cat"));
}
}Common mistakes
List<int>
The compiler rejects
List<int>withunexpected type. Only classes go in angle brackets:List<Integer>,Map<String, Double>.remove on a List<Integer>
There are two
removemethods: with anintit removes a position, with an object it removes the element. With a list of numbers, that's a trap:List<Integer> numbers = new ArrayList<>(List.of(10, 20, 30)); numbers.remove(1); // removes position 1: [10, 30] numbers.remove(Integer.valueOf(10)); // removes the value 10: [30]Changing a list inside for-each
If you remove or add elements while a for-each loop runs over the same list, the program stops with
ConcurrentModificationException. Use a normalforloop with an index, or collect into a new list.A missing key gives null
int n = counts.get("dog");stops withNullPointerExceptionif the key doesn't exist, becausenullis not a number. UsegetOrDefault(key, 0)or checkcontainsKeyfirst.Order in HashMap and HashSet
HashMapandHashSetdon't remember the order in which you added things. Don't rely on it in your output. If you need the order, useLinkedHashSetorLinkedHashMap.