A list that grows
Problem
The cart is full
You are writing the shopping cart of an online store, and you keep the items in an array. But an array has a size that does not change. When the customer adds a fourth item, you make a bigger array and copy everything. When they remove an item, a hole is left:
String[] cart = { "Bread", "Milk", "Coffee" };
// A fourth item: the array is full, so we make a bigger one and copy.String[] bigger = new String[cart.length + 1];for (int i = 0; i < cart.length; i++) { bigger[i] = cart[i];}bigger[cart.length] = "Butter";cart = bigger;
// The customer removes the milk.cart[1] = null;
for (String item : cart) { System.out.println(item);}BreadnullCoffeeButternull. And the number of items is no longer cart.length.That is a lot of code for something every store does all the time.
The idea
ArrayList: an array that looks after itself
Java has a ready-made class for this: ArrayList. It keeps the elements in an array, but it does the copying and shifting by itself. A collection like this is called a list:
import java.util.ArrayList;
public class Main { public static void main(String[] args) { ArrayList<String> cart = new ArrayList<>(); cart.add("Bread"); cart.add("Milk"); cart.add("Coffee"); cart.add("Butter"); cart.remove("Milk"); System.out.println(cart); System.out.println("Items: " + cart.size()); }}[Bread, Coffee, Butter]Items: 3ArrayListis in thejava.utilpackage, so the file starts with animport, as withScanner.addadds at the end, andremoveremoves and closes the hole: "Coffee" moves into the place of "Milk".size()is how many elements there are right now. It is notlength, because a list is not an array.printlnprints the whole list in square brackets.
Here is what ArrayList does inside. The number in the parentheses is the starting size of the array. Without it, it is 10. Here it is 3, so you can see what happens when the array fills up:
ArrayList<String> cart = new ArrayList<>(3);cart.add("Bread");cart.add("Milk");cart.add("Coffee");cart.add("Butter");cart.remove("Milk");System.out.println(cart);System.out.println("Items: " + cart.size());Step by step, in words
- cart points to an ArrayList object. Inside there is an array with 3 places and a size counter.
- add puts each element in the first free place and increases size.
- The array is full. ArrayList makes a new one with 4 places and copies the three elements into it.
- The object now points to the new array, and nobody needs the old one. "Butter" goes into the free place.
- remove removes "Milk", and everything after it moves one place to the left. No hole is left.
- From the outside you see only a list of three items: ArrayList does the copying and the shifting.
The idea
What goes in the angle brackets
ArrayList<String> means "a list of text". The type in the angle brackets is called a type parameter (generics). It tells the compiler what is in the list, and the compiler enforces it:
import java.util.ArrayList;
public class Main { public static void main(String[] args) { ArrayList<String> cart = new ArrayList<>(); cart.add("Bread"); cart.add(5); }}Main.java:7: error: incompatible types: int cannot be converted to String cart.add(5); ^That is why cart.get(0) returns a String directly, with no conversion.
On the right, the angle brackets are empty: new ArrayList<>(). The compiler takes the type from the left side.
Usually the variable is declared with the List interface, and the ArrayList class appears only after new:
List<String> cart = new ArrayList<>();cart.add("Bread");System.out.println(cart.get(0));This is the polymorphism from the "Inheritance" module: List says what a list can do, and ArrayList is one way of doing it. You need two imports: java.util.ArrayList and java.util.List. From here on, the lesson does not show them.
The idea
Indexes: get, set, add, indexOf
A list has indexes like an array, from 0 to size() - 1. But instead of [ ] you use methods:
List<String> tasks = new ArrayList<>();tasks.add("March invoice");tasks.add("Call the bank");tasks.add("Warehouse report");
System.out.println(tasks.get(0));tasks.set(1, "Meeting at the bank");tasks.add(0, "Coffee with the team");System.out.println(tasks);System.out.println(tasks.indexOf("Warehouse report"));System.out.println(tasks.contains("Call the bank"));March invoice[Coffee with the team, March invoice, Meeting at the bank, Warehouse report]3falseget(i)reads, andset(i, x)replaces.add(i, x)inserts at indexiand shifts the rest to the right.indexOf(x)searches and returns the index or-1, andcontains(x)only says whether it is there.
More precisely, if you are curious
- An index outside the list stops the program, as with an array:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 3 out of bounds for length 3containsandindexOfcompare withequals, not with==. That is why they find text that is equal, not only the same object.- Inserting and removing at the front are slow in a big list: every element after the index moves by one place. For a million elements, that is a million moves.
Try it
Who is next?
The list of patients waiting at the doctor's. Ivan goes in, and Ana has an appointment, so she takes second place.
What will the program print?
List<String> waiting = new ArrayList<>();waiting.add("Ivan");waiting.add("Maria");waiting.add("Peter");waiting.remove(0);waiting.add(1, "Ana");System.out.println(waiting + " " + waiting.size());remove(0) removes Ivan, and Maria becomes first, at index 0. add(1, "Ana") inserts Ana at index 1 and pushes Peter to the right. Three are left.
The idea
Looping over the elements
You loop over a list like an array: with for-each when you need only the elements, or with an index when you also need the number:
List<String> cart = new ArrayList<>();cart.add("Bread");cart.add("Coffee");cart.add("Butter");
for (String item : cart) { System.out.println("- " + item);}for (int i = 0; i < cart.size(); i++) { System.out.println((i + 1) + ". " + cart.get(i));}- Bread- Coffee- Butter1. Bread2. Coffee3. ButterMore precisely, if you are curious
- Do not remove elements from a list while you loop over it with for-each. The program stops:
for (String item : cart) { if (item.equals("Bread")) { cart.remove(item); }}Exception in thread "main" java.util.ConcurrentModificationExceptionThe exception does not always come. If you remove the second to last element, the loop stops early and the last one is never checked. So do not rely on it.
- If you have to remove, loop with an index from the back to the front. That way, removing does not shift the elements you have not checked yet:
List<String> cart = new ArrayList<>();cart.add("Bread");cart.add("Milk");cart.add("Bread");for (int i = cart.size() - 1; i >= 0; i--) { if (cart.get(i).equals("Bread")) { cart.remove(i); }}System.out.println(cart);[Milk]removeIf.The idea
Numbers in a list: Integer
A list of scores looks like this, but it does not compile:
ArrayList<int> scores = new ArrayList<>();Main.java:5: error: unexpected type ArrayList<int> scores = new ArrayList<>(); ^ required: reference found: intThe angle brackets need a class, and int is not a class. So every primitive type has a wrapper class: Integer for int, Double for double, Boolean for boolean, Character for char.
List<Integer> scores = new ArrayList<>();scores.add(85);scores.add(64);scores.add(91);
int total = 0;for (int score : scores) { total += score;}System.out.println("Average: " + (double) total / scores.size());Average: 80.0scores.add(85) gets an int, but the list wants an Integer. Java puts it in a wrapper by itself. This is called autoboxing. In the loop, int score is the opposite: unboxing. Almost always, you do not notice the difference.
More precisely, if you are curious
- Compare
Integervalues withequals, not with==.==checks whether the two variables point to the same object:
Integer a = 127, b = 127;Integer c = 128, d = 128;System.out.println(a == b);System.out.println(c == d);System.out.println(c.equals(d));truefalsetrueJava keeps ready-made objects for the numbers from -128 to 127, so at 127 both arrows point to one object. At 128 there are two objects.
- An
Integercan benull, and anintcannot. If you unboxnull, the program stops withNullPointerException. You will run into this in the lesson onHashMap.
Try it
Find the bug
A theater keeps the taken seats in a list. A customer gives up seat 2, and the program should print [12, 7, 5]. Instead it prints [12, 2, 5]. Which line has the bug?
Pick the line with the bug.
List has two remove methods: remove(int index) and remove(Object o). In remove(2) the argument is an int, so the first one is called, and it removes the element at index 2, which is seat 7. To remove the value 2, pass an object: seats.remove(Integer.valueOf(2)). A List<String> does not have this trap, because text is never an index.The idea
Sorting and a ready-made list
Collections.sort sorts the list in place: text in alphabetical order, numbers by size. The Collections class is in java.util too.
List<String> cities = new ArrayList<>();cities.add("Sofia");cities.add("Plovdiv");cities.add("Varna");Collections.sort(cities);System.out.println(cities);
List<Integer> prices = new ArrayList<>(List.of(30, 5, 12));Collections.sort(prices);System.out.println(prices);[Plovdiv, Sofia, Varna][5, 12, 30]List.of(30, 5, 12) makes a ready-made list from the values you list. But it is immutable: you cannot add, remove or sort in it.
List<String> days = List.of("Mon", "Tue", "Wed");days.add("Thu");Exception in thread "main" java.lang.UnsupportedOperationExceptionThat is why the prices above are copied into a new ArrayList: new ArrayList<>(List.of(30, 5, 12)) is a list you can change.
More precisely, if you are curious
- Text is sorted by the codes of its characters. Capital letters come before lowercase ones, so "Pear" comes before "apple":
List<String> fruit = new ArrayList<>(List.of("apple", "Pear", "banana", "Grape"));Collections.sort(fruit);System.out.println(fruit);[Grape, Pear, apple, banana]- How to sort your own objects, for example products by price, you will see in the lesson "Classes inside classes".
Exercise
Lists in classes
private field of the class, and main only calls its methods.1. A bookshelf. A BookShelf class with a addBook(String title) method that puts the book at the end, and takeBook(), which returns and removes the first book (or null if the shelf is empty). Add count() and toString(). In main, add "Under the Yoke", "Tobacco" and "The Iron Candlestick", take one book and print the rest.
Took: Under the Yoke2 left: [Tobacco, The Iron Candlestick]2. An event log. An Event class with a date and a description, and an EventLog class with the methods addEvent(String date, String description) and getEventsBetween(String from, String to), which returns a list of the events between the two dates, inclusive. The dates are text in the form 2026-03-31. In this form, the text sorts the same way as the dates, so compareTo from the lesson on text compares them correctly. Add four events: 2026-01-15 "Annual stocktake", 2026-03-31 "First quarter report", 2026-05-20 "New coffee supplier", 2026-09-01 "New school year". Print the ones from 2026-03-01 to 2026-06-30.
2026-03-31 First quarter report2026-05-20 New coffee supplier3. A notebook. A Note class with a title and content, and a Notebook class with the methods addNote, findNote(String title) (returns the note or null), deleteNote(String title) (returns true if it deleted something) and count(). Add the notes "OOP", "Collections" and "SQL", find "Collections", delete "OOP" and check that it is gone.
Collections: ArrayList grows by itselfDeleted: OOPNotes: 2There is no OOP note.4. Mental math. A Question class with a text and the right answer, and a MathGame class with a list of questions, an addQuestion method and a start(Scanner in) method. start asks the questions one by one, reads the answer and at the end says how many were right. The questions are 2 + 2, 3 * 4 and 15 - 9.
41272 + 2 = Correct!3 * 4 = Correct!15 - 9 = Wrong, the answer is 6.Score: 2 out of 3More tasks
- No repeats. Read 6 names and collect them in a list, skipping the ones that are already in it. For the input Ivan, Maria, Ivan, Ana, Maria, Peter the output is
[Ivan, Maria, Ana, Peter]. - The most expensive item. A List<Double> holds prices. Find the highest one and its index, without
Collections. - Reverse the list. Write a method that returns a new list with the same elements in reverse order. Do not change the original.
- A shopping list. Read the commands
add milk,remove milk,listandend, and keep the list between them. The command to remove an item that is not there says "No such item."
Test