ArrayList
IB Syllabus: B2.2.2 – Construct programs that apply ArrayLists: add, remove, and traverse elements in a dynamic list.
Key Concepts
Why ArrayList?
Arrays have a fixed size – once created, they cannot grow or shrink. This is a problem when you do not know how many elements you will need at compile time.
String[] names = new String[5]; // exactly 5 slots -- what if we need 6?
An ArrayList is a dynamic list that grows and shrinks automatically. You can add elements without worrying about capacity, and remove elements without leaving gaps.
import java.util.ArrayList;
ArrayList<String> names = new ArrayList<>(); // starts empty, grows as needed
names.add("Alice"); // size is now 1
names.add("Bob"); // size is now 2
names.remove(0); // size is now 1
When to use an array: You know the exact size at creation time (e.g., days of the week, fixed grid). When to use an ArrayList: The size changes at runtime (e.g., student roster, shopping cart, search results).
You Already Know This Pattern
You have already used import, new, and .method() with Scanner and String. ArrayList follows the same pattern:
// Scanner (you already know this):
import java.util.Scanner; // import from java.util
Scanner input = new Scanner(System.in); // create with new
input.nextLine(); // call methods with dot notation
// ArrayList (same pattern):
import java.util.ArrayList; // import from java.util
ArrayList<String> names = new ArrayList<>(); // create with new
names.add("Alice"); // call methods with dot notation
The <String> part (called generics) tells Java what type of data the list holds. We will understand the full reason when we cover OOP – for now it is the same kind of “just use it” rule as public static void main.
Static vs Dynamic Data Structures (B2.2.1)
| Static (Array) | Dynamic (ArrayList) | |
|---|---|---|
| Size | Fixed at creation | Grows and shrinks automatically |
| Memory | Block allocated upfront | Allocates as needed |
| Speed | Faster access (direct index) | Slightly slower (overhead) |
| Flexibility | Must know size in advance | Add/remove freely |
| Syntax | int[] grades = new int[30]; | ArrayList<Integer> grades = new ArrayList<>(); |
Connection to Hardware: Remember how RAM works – memory is allocated in blocks. A static array reserves a fixed block upfront (even if you do not fill it). A dynamic list requests more memory as it grows. This is why arrays are faster (one contiguous block) but less flexible.
Declaring an ArrayList
import java.util.ArrayList;
ArrayList<String> names = new ArrayList<>();
ArrayList<Integer> scores = new ArrayList<>();
ArrayList<Double> prices = new ArrayList<>();
Key syntax:
- Import
java.util.ArrayList - Specify the element type in angle brackets:
<String>,<Integer>,<Double> - Use
new ArrayList<>()with the diamond operator (Java infers the type)
Wrapper Types
ArrayLists store objects, not primitives. Java provides wrapper classes for each primitive type:
| Primitive | Wrapper Class |
|---|---|
int | Integer |
double | Double |
boolean | Boolean |
char | Character |
ArrayList<Integer> scores = new ArrayList<>(); // Integer, not int
scores.add(95); // Java auto-converts 95 to Integer (autoboxing)
int s = scores.get(0); // Java auto-converts Integer to int (unboxing)
Use Integer, not int, in the angle brackets. ArrayList<int> is a compile error.
ArrayList needs wrapper classes (Integer, not int) because it stores objects. String is already an object, so ArrayList<String> needs no wrapper. We will learn more about objects vs primitives when we study OOP.
Core Operations
Adding Elements
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Apple"); // adds to the end -> [Apple]
fruits.add("Banana"); // adds to the end -> [Apple, Banana]
fruits.add("Cherry"); // adds to the end -> [Apple, Banana, Cherry]
fruits.add(1, "Mango"); // inserts at index 1 -> [Apple, Mango, Banana, Cherry]
add(element) appends to the end. add(index, element) inserts at a specific position, shifting existing elements right.
Accessing Elements
String first = fruits.get(0); // "Apple"
String second = fruits.get(1); // "Mango"
Use .get(index), not [index]. Square bracket access does not work with ArrayList.
Updating Elements
fruits.set(1, "Pear"); // replaces index 1 -> [Apple, Pear, Banana, Cherry]
Removing Elements
fruits.remove(2); // removes by index -> [Apple, Pear, Cherry]
fruits.remove("Cherry"); // removes by value -> [Apple, Pear]
Removing shifts all elements after the removed one to the left. Indices of later elements change.
Size
int count = fruits.size(); // 2
Use .size(), not .length. This is one of the most common mistakes. Watch out for the three-way trap:
| Structure | How to get the count |
|---|---|
| Array | arr.length (no parentheses) |
| ArrayList | list.size() (parentheses) |
| String | str.length() (parentheses) |
Checking Contents
boolean hasPear = fruits.contains("Pear"); // true
int pos = fruits.indexOf("Apple"); // 0 (or -1 if not found)
Connections to String methods: indexOf() returns -1 when not found – the same convention as String.indexOf(). contains() returns a boolean, similar to how you use String.equals() to check for a match.
Traversing an ArrayList
Standard for Loop
for (int i = 0; i < names.size(); i++) {
System.out.println(names.get(i));
}
Enhanced for Loop (for-each)
for (String name : names) {
System.out.println(name);
}
The enhanced for loop is shorter but you cannot access the index or modify the list during traversal.
Removing During Traversal
Removing elements while looping forward causes problems because indices shift. Loop backwards instead:
for (int i = names.size() - 1; i >= 0; i--) {
if (names.get(i).equals("Bob")) {
names.remove(i);
}
}
Never remove elements in a forward loop without adjusting the index. You will skip elements or get an IndexOutOfBoundsException.
Worked Examples
Example 1: Student Roster
A teacher needs to manage a class list that changes as students join and leave.
import java.util.ArrayList;
ArrayList<String> students = new ArrayList<>();
// Students enroll
students.add("Alice");
students.add("Bob");
students.add("Charlie");
students.add("Diana");
System.out.println("Enrolled: " + students.size()); // 4
// Bob transfers out
students.remove("Bob");
System.out.println("After transfer: " + students.size()); // 3
// New student joins
students.add("Eve");
// Print the roster
for (int i = 0; i < students.size(); i++) {
System.out.println((i + 1) + ". " + students.get(i));
}
Output:
Enrolled: 4
After transfer: 3
1. Alice
2. Charlie
3. Diana
4. Eve
Example 2: Filtering a List
Find all scores above 80 from a list of test results.
public static ArrayList<Integer> getHighScores(ArrayList<Integer> scores) {
ArrayList<Integer> high = new ArrayList<>();
for (int i = 0; i < scores.size(); i++) {
if (scores.get(i) > 80) {
high.add(scores.get(i));
}
}
return high;
}
Example 3: Calculating an Average
public static double getAverage(ArrayList<Integer> scores) {
if (scores.size() == 0) {
return 0;
}
int total = 0;
for (int i = 0; i < scores.size(); i++) {
total += scores.get(i);
}
return (double) total / scores.size();
}
Array vs ArrayList Comparison
| Feature | Array | ArrayList |
|---|---|---|
| Size | Fixed at creation | Grows/shrinks dynamically |
| Declaration | int[] arr = new int[5]; | ArrayList<Integer> list = new ArrayList<>(); |
| Access | arr[i] | list.get(i) |
| Update | arr[i] = value; | list.set(i, value) |
| Length/Size | arr.length | list.size() |
| Add element | Not possible (fixed) | list.add(value) |
| Remove element | Not possible (fixed) | list.remove(index) |
| Stores primitives | Yes | No (uses wrapper classes) |
| Performance | Faster (direct memory) | Slightly slower (object overhead) |
Rule of thumb: Use arrays when the size is known and fixed. Use ArrayList when the size changes.
Preview: ArrayList of Objects
This section is a forward reference. You will learn about classes and objects when we cover OOP. For now, just notice that ArrayList is not limited to String and Integer.
When you learn OOP, you will write your own classes and store them in ArrayLists:
ArrayList<Student> roster = new ArrayList<>();
roster.add(new Student("Alice", 90));
roster.add(new Student("Bob", 85));
// Find a student by name
for (int i = 0; i < roster.size(); i++) {
if (roster.get(i).getName().equals("Alice")) {
System.out.println("Found: " + roster.get(i).getGrade());
}
}
This is the same pattern as using arrays of objects, but with get() instead of [i] and no need to track a separate count variable – .size() always returns the current number of elements. ArrayList + OOP is how real Java applications manage data.
Quick Check
Q1. Why does ArrayList<int> cause a compile error?
Q2. How do you get the number of elements in an ArrayList called items?
Q3. Given list = [Apple, Banana, Cherry], what is the list after list.remove(1)?
Q4. Given list = [Apple, Banana], what is the list after list.add(1, "Mango")?
Q5. Why should you loop backwards when removing elements from an ArrayList?
Trace Exercise
Trace the state of the ArrayList after each operation.
Trace: Track the contents and size of the ArrayList after each line.
ArrayList<String> list = new ArrayList<>();
list.add("Red"); // Line 1
list.add("Blue"); // Line 2
list.add("Green"); // Line 3
list.add(1, "Yellow"); // Line 4
list.remove(2); // Line 5
list.set(0, "Purple"); // Line 6| After Line | List Contents | Size |
|---|---|---|
| 1 | [Red] | 1 |
| 2 | [Red, Blue] | 2 |
| 3 | [Red, Blue, Green] | |
| 4 | ||
| 5 | ||
| 6 |
Code Completion
Complete the method that removes all occurrences of a value from an ArrayList.
Fill in the blanks: Remove all students with a failing grade (below 50).
public static void removeFailing(ArrayList<Integer> grades) {
for (int i = grades. - 1; i >= 0; i--) {
if (grades. < 50) {
grades.;
}
}
} Spot the Error
This code should print all names in the list, but it crashes.
Bug Hunt: This code does not compile. Find the error.
Pick the correct fix for line 2:
Bug Hunt: This line does not compile. Find the error.
Pick the correct fix for line 1:
Bug Hunt: This code tries to remove all elements, but it leaves [B] in the list. Find the error.
Pick the correct fix for line 3:
Predict the Output
Predict: What does this code print?
ArrayList<Integer> nums = new ArrayList<>();
nums.add(10);
nums.add(20);
nums.add(30);
nums.add(1, 40);
nums.remove(2);
System.out.println(nums.get(1)); Predict: What does this code print?
ArrayList<String> names = new ArrayList<>();
names.add("Apple");
names.add("Banana");
names.add("Cherry");
for (int i = names.size() - 1; i >= 0; i--) {
System.out.println(names.get(i));
} Practice Exercises
Core
-
Number collector – Construct a program that reads integers from the user until they type -1. Store the numbers in an
ArrayList<Integer>. Print the sum, average, maximum, and minimum. [5 marks] -
Word filter – Construct a method
filterShort(ArrayList<String> words, int minLength)that removes all words shorter thanminLengthcharacters. Print the filtered list. [4 marks] -
Score tracker – Construct a method
getAverage(ArrayList<Integer> scores)that returns the average as adouble. [3 marks]
Extension
-
Unique list – Construct a program that reads strings from the user. Only add a string if it is not already in the list (use
.contains()). Print the final list of unique items. [4 marks] -
Reverse without reversing – Construct a method that accepts an
ArrayListand returns a newArrayListwith the elements in reverse order. Do not useCollections.reverse. [4 marks]
Challenge
- Merge two sorted lists – Construct a method that accepts two sorted
ArrayList<Integer>and returns one sortedArrayListcontaining all elements from both. Do not use any sort method. [6 marks]
Exam-Style [16 marks]
A teacher stores student names in an
ArrayList<String>and their scores in a parallelArrayList<Integer>(same index = same student).(a) Construct a method
addStudent(ArrayList<String> names, ArrayList<Integer> scores, String name, int score)that adds a student and their score to the lists. [2](b) Construct a method
getAverage(ArrayList<Integer> scores)that returns the class average as adouble. [3](c) Construct a method
getAboveAverage(ArrayList<String> names, ArrayList<Integer> scores)that returns a newArrayList<String>containing only the names of students who scored above the average. [4](d) Explain one advantage of using
ArrayListinstead of arrays for this program. [1](e) Describe the steps required to remove all students who scored below a given threshold from both ArrayLists. You are not required to write code. [4]
(f) Outline one situation where a standard array would be a better choice than
ArrayList. [2]
GitHub Classroom
Codespace Setup Instructions (click to expand)
First Time Setup
- Click “Open in GitHub” above, then click the green “Accept this assignment” button
- Check the email registered with your GitHub account – click the link there to open your repository. This avoids access issues and means your teacher does not need to share links manually
- Wait for your repository to be created, then click “Open in Codespace”
- Wait for the Codespace to finish loading (you’ll see VS Code in your browser)
Important: Switch to Standard Mode
- Look at the bottom status bar. If it says
Java: Lightweight Mode, click on it and select Standard - Wait for Java to finish loading (status bar will say
Java: Ready) - Without Standard Mode, the Run button won’t work and you’ll get “Main method not found” errors
Dismiss Popups
You’ll see two notification popups. Dismiss them both:
- “Would you like VS Code to periodically run git fetch?” → Click No
- “There’s a pull request associated with main” → Click Don’t Show Again
These are housekeeping popups, not part of the assignment.
How to Code
- Open
src/NumberCollector.java. This is the only file you need to edit - Complete each
// TODOsection usingArrayList<Integer>and a sentinel loop - Click the Run button (▶ above
main) to test your output - Compare your output with the expected output written in the comments above each task
There are 7 exercise files in src/ – start with NumberCollector.java and work through the tiers.
How to Check Your Code
You can check your work in two ways:
Option A: Run your code directly
- Click the Run button (▶) above
maininNumberCollector.java - Compare your printed output with the expected output shown in the comments above each task
Option B: Run the autograder tests
- Open the Terminal (Menu → Terminal → New Terminal)
- Type
bash run-tests.shand press Enter - Green ✓ = test passed, Red ✗ = test failed
- Each test tells you what it expected. Read the error message to fix your code
How to Submit
- Click the Source Control icon (branch icon) in the left sidebar
- Type a message like
completed tasksin the message box - Click the green Commit button
- If asked “stage all changes?” → click Always
- Click Sync Changes → if asked about push/pull → click OK, Don’t Show Again
- Done! Autograding runs automatically. Your teacher can see your results in the GitHub Classroom dashboard
How to Review Feedback
- Go to your repository on GitHub
- Click the “Pull requests” tab at the top
- Open the pull request called “Feedback”
- Click the “Files changed” tab. You’ll see your teacher’s comments on specific lines of your code
- Read through each comment carefully, then fix your code in Codespaces
- Run
bash run-tests.shin your Codespaces Terminal to check your fixes - Commit and push again (repeat steps 12-17). The autograder will re-run automatically
Connections
- Prerequisites: 1D Arrays – fixed-size arrays and traversal
- Prerequisites: Strings –
.equals()for comparing elements,indexOf()returning -1,length()vssize() - Prerequisites: Methods – ArrayList methods use the same call patterns (parameters, return values)
- Related: Primary Memory – static vs dynamic memory allocation (RAM blocks)
- Related: Exception Handling – IndexOutOfBoundsException on invalid index
- Forward: File Processing – reading unknown number of lines from a file into an ArrayList
- Forward: OOP Aggregation – ArrayList of objects in a container class
- Forward: Stacks – Stack uses similar CRUD patterns
- Forward: Queues – Queue uses similar CRUD patterns