A Java array (int[]) has a fixed size: you cannot add an element once it is created. In a real program (a shopping cart, a list of students, the lines of a file), you do not know the size in advance. The Collections framework (java.util) addresses this need, and the most widely used collection is the list.
Declaring a list
import java.util.ArrayList;
import java.util.List;
List<String> courses = new ArrayList<>(); // interface on the left, implementation on the right
courses.add("bread"); // adds at the end
courses.add("milk");
courses.add(0, "coffee"); // inserts at index 0
System.out.println(courses); // [coffee, bread, milk]
System.out.println(courses.get(1)); // bread
courses.set(1, "baguette"); // replaces the element at index 1
System.out.println(courses.size()); // 3
System.out.println(courses.contains("milk")); // true
Since Java 21, lists are sequenced collections: they offer shortcuts for the ends, more readable than get(0) or get(list.size() - 1):
courses.getFirst(); // "coffee" (NoSuchElementException if the list is empty)
courses.getLast(); // "milk"
courses.addFirst("tea"); // equivalent to add(0, "tea")
courses.reversed(); // view in reverse order: [milk, baguette, coffee, tea]
The <String> is a generic type: the compiler refuses to add anything other than a String, and get returns a String directly, without casting. The diamond operator <> avoids repeating the type.
Generics accept only objects: you write List<Integer>, not List<int>. Java automatically converts int to Integer (autoboxing).
Why declare with
Listrather thanArrayList? So you can switch implementations (for example toLinkedList) without touching the rest of the code. This is the principle of “programming to an interface”.
The remove trap
List<Integer> notes = new ArrayList<>(List.of(10, 20, 30));
notes.remove(1); // removes the element at INDEX 1 -> [10, 30]
notes.remove(Integer.valueOf(30)); // removes the VALUE 30 -> [10]
Immutable lists
List.of("a", "b") creates an unmodifiable list: add or remove throws an UnsupportedOperationException. This is ideal for constants or for returning data you do not want modified. To get a modifiable copy: new ArrayList<>(List.of(...)). For an immutable copy of an existing list: List.copyOf(list).
Iterating and removing safely
for (String article : courses) {
System.out.println("- " + article);
}
// Classic ERROR: removing during a for-each
// for (String a : courses) { if (a.startsWith("b")) courses.remove(a); }
// -> ConcurrentModificationException
courses.removeIf(a -> a.startsWith("b")); // the right way
removeIf takes a condition (a lambda, which we will cover in depth in lesson 3) and removes all the elements that satisfy it.
Key takeaways
ArrayListis the default list: fast index access, fast append.- Declare with the
List<T>interface. List.of= immutable;new ArrayList<>(...)= modifiable.- No removal inside a for-each: use
removeIf.
Exercises
Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.
Clean a list of measurements
Read a line of integers separated by spaces. Store them in a
List<Integer>, remove the negative values withremoveIf, then print:[3, 4, 9] taille=3 somme=16(the list with
System.out.println(list), then its size, then the sum). An empty line gives an empty list.import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String ligne = sc.hasNextLine() ? sc.nextLine().trim() : ""; List<Integer> mesures = new ArrayList<>(); // TODO : remplir la liste, supprimer les négatifs, afficher } }Shopping list driven by commands
Each input line is a command:
ADD x: appendsxat the end;INSERT i x: insertsxat indexi;REMOVE x: removes the first occurrence ofx, or printsabsent: xif it does not exist.
At the end, print the list numbered from 1 (
1. pain). If the list is empty, printliste vide.import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); List<String> courses = new ArrayList<>(); while (sc.hasNextLine()) { String[] p = sc.nextLine().trim().split(" "); // TODO : traiter ADD, INSERT et REMOVE } // TODO : afficher la liste numérotée } }Immutable list
What happens when
List<String> l = List.of("a"); l.add("b");runs?- The list contains [a, b]
- An UnsupportedOperationException is thrown
- The code does not compile
- add returns false without changing anything
End-of-lesson quiz
Which declaration is recommended?
- ArrayList<String> l = new ArrayList<String>();
- List<String> l = new ArrayList<>();
- List l = new ArrayList();
On a List
equal to [5, 6, 7], what does remove(1) give? - [6, 7]
- [5, 7]
- [5, 6, 7]
How do you remove all empty elements from a modifiable List
? - In a for-each with list.remove(s)
- liste.removeIf(String::isEmpty)
- liste.delete("")
The rest of the course
- Sets and Dictionaries: Set and Map18 min
- Lambdas, Comparator, and Your First Streams18 min
- Collectors, Grouping, and Optional18 min
- Handling Errors with Exceptions20 min