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 LineList ContentsSize
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.

1ArrayList<String> names = new ArrayList<>(); 2for (int i = 0; i < names.length; i++) { 3 System.out.println(names.get(i)); 4}

Pick the correct fix for line 2:

Bug Hunt: This line does not compile. Find the error.

1ArrayList<int> numbers = new ArrayList<>(); 2numbers.add(42); 3numbers.add(17);

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.

1ArrayList<String> list = new ArrayList<>(); 2list.add("A"); list.add("B"); list.add("C"); 3for (int i = 0; i < list.size(); i++) { 4 list.remove(i); 5}

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

  1. 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]

  2. Word filter – Construct a method filterShort(ArrayList<String> words, int minLength) that removes all words shorter than minLength characters. Print the filtered list. [4 marks]

  3. Score tracker – Construct a method getAverage(ArrayList<Integer> scores) that returns the average as a double. [3 marks]

Extension

  1. 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]

  2. Reverse without reversing – Construct a method that accepts an ArrayList and returns a new ArrayList with the elements in reverse order. Do not use Collections.reverse. [4 marks]

Challenge

  1. Merge two sorted lists – Construct a method that accepts two sorted ArrayList<Integer> and returns one sorted ArrayList containing 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 parallel ArrayList<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 a double. [3]

(c) Construct a method getAboveAverage(ArrayList<String> names, ArrayList<Integer> scores) that returns a new ArrayList<String> containing only the names of students who scored above the average. [4]

(d) Explain one advantage of using ArrayList instead 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

ArrayList Exercises
Practice ArrayList operations: number collector, word filter, score tracker, unique list, reverse, merge sorted, and a multi-part grade tracker exam-style question.
Codespace Setup Instructions (click to expand)

First Time Setup

  1. Click “Open in GitHub” above, then click the green “Accept this assignment” button
  2. 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
  3. Wait for your repository to be created, then click “Open in Codespace”
  4. Wait for the Codespace to finish loading (you’ll see VS Code in your browser)

Important: Switch to Standard Mode

  1. Look at the bottom status bar. If it says Java: Lightweight Mode, click on it and select Standard
  2. Wait for Java to finish loading (status bar will say Java: Ready)
  3. 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

  1. Open src/NumberCollector.java. This is the only file you need to edit
  2. Complete each // TODO section using ArrayList<Integer> and a sentinel loop
  3. Click the Run button (▶ above main) to test your output
  4. 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 main in NumberCollector.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.sh and 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

  1. Click the Source Control icon (branch icon) in the left sidebar
  2. Type a message like completed tasks in the message box
  3. Click the green Commit button
  4. If asked “stage all changes?” → click Always
  5. Click Sync Changes → if asked about push/pull → click OK, Don’t Show Again
  6. Done! Autograding runs automatically. Your teacher can see your results in the GitHub Classroom dashboard

How to Review Feedback

  1. Go to your repository on GitHub
  2. Click the “Pull requests” tab at the top
  3. Open the pull request called “Feedback”
  4. Click the “Files changed” tab. You’ll see your teacher’s comments on specific lines of your code
  5. Read through each comment carefully, then fix your code in Codespaces
  6. Run bash run-tests.sh in your Codespaces Terminal to check your fixes
  7. 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() vs size()
  • 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

© EduCS.me — A resource hub for Computer Science education

This site uses Just the Docs, a documentation theme for Jekyll.