1. LxD Cycle Process

Empathize: Students can already write array code, so they reach for scores[2] and scores.length on an ArrayList and hit a compiler error. The two remove methods are a second trap: values.remove(1) and values.remove(Integer.valueOf(1)) look almost the same but do different things, and a student who does not notice can delete the wrong element with no error at all.

Define:

  • POV: CSA students need the five core ArrayList methods (add, get, set, remove, size) mapped explicitly onto what they already know from arrays, because every mismatch (.length vs .size(), list[i] vs list.get(i), remove(index) vs remove(Object)) is either a compiler error or a silent bug.
  • Learning Goal: Students will declare an ArrayList, add elements with add, read and change elements with get and set, remove elements with either remove overload, and check length with size().

Ideate:

  • HMW Question: How might we make the array.length vs list.size() mismatch visible instead of just told?
  • HMW Question: How might we surface the difference between remove(int index) and remove(Object obj) before it causes a silent bug in a student’s own code?
  • Activity: Compare a fixed array to a growing ArrayList side by side, predict output before every run, then use both remove overloads on the same list and compare results.

Prototype & Test: Lesson authors: add what happened in your trial run and what you changed.


2. Lesson Plan

Learning Objective: Declare an ArrayList and use add, get, set, remove, and size to build and change it correctly.

Success Criteria: You can add elements at the end or at a specific index, read and replace an element without changing the list’s size, remove an element by index or by value using the correct remove overload, and explain why ArrayList uses size() instead of length.

Before you start: arrays, wrapper classes (Integer, Double), and generic types written as ArrayList<Type>.

Tech Talk (5 minutes)

An array is created with a fixed length. A grocery list grows every time you think of something new and shrinks every time you cross something off. ArrayList is built for data that changes size while a program runs.

ArrayList<String> groceries = new ArrayList<String>(); // empty list
groceries.add("Milk");                                 // add to the end
groceries.add(0, "Eggs");                               // insert at index 0
String first = groceries.get(0);                        // read: "Eggs"
groceries.set(1, "Oat Milk");                            // replace index 1
groceries.remove(0);                                     // remove by index
System.out.println(groceries.size());                    // count elements

ArrayList<E> is a generic type: the E you put in the angle brackets is the type every element must be, and it is why ArrayList<String> names = new ArrayList<String>(); lets the compiler catch type mistakes that would otherwise only show up when the program runs. ArrayList lives in java.util, so using it outside a scratch cell like these requires import java.util.ArrayList;.

From the College Board

AP CSA Unit 4, Topic 4.8 focuses on ArrayList methods. Quoted from the course and exam description (College Board, 2025, pp. 110-111):

  • 4.8.A.1 “An ArrayList object is mutable in size and contains object references.”
  • 4.8.A.3 “Java allows the generic type ArrayList<E>, where the type parameter E specifies the type of the elements. … ArrayList<E> is preferred over ArrayList. For example, ArrayList<String> names = new ArrayList<String>(); allows the compiler to find errors that would otherwise be found at run-time.”
  • 4.8.A.6 “The indices for an ArrayList start at 0 and end at the number of elements - 1.”

Essential knowledge 4.8.A.5 places these method signatures on the Java Quick Reference, quoted exactly as printed (College Board, 2025, p. 111):

Method Quoted description
int size() “returns the number of elements in the list.”
boolean add(E obj) “appends obj to end of list; returns true.”
void add(int index, E obj) “inserts obj at position index (0 <= index <= size), moving elements at position index and higher to the right (adds 1 to their indices) and adds 1 to size.”
E get(int index) “returns the element at position index in the list.”
E set(int index, E obj) “replaces the element at position index with obj; returns the element formerly at position index.”
E remove(int index) “removes element from position index, moving elements at position index + 1 and higher to the left (subtracts 1 from their indices) and subtracts 1 from size; returns the element formerly at position index.”

3. Reference Guide

Key Vocabulary

Term Definition Example
ArrayList Resizable list of object references; part of java.util. ArrayList<Integer> nums = new ArrayList<Integer>();
Generic type The <E> in ArrayList<E> that fixes the element type at compile time. ArrayList<String> only holds String
size() Method that returns the number of elements currently stored. nums.size()
Index Position of an element, from 0 to size() - 1. nums.get(0)
IndexOutOfBoundsException Runtime error from get/set/remove at an invalid index. nums.get(nums.size())

Array vs. ArrayList

  Array ArrayList
Size Fixed at creation Grows and shrinks
Element count .length (field) .size() (method)
Read/write arr[i] list.get(i) / list.set(i, v)
Add/remove Not possible after creation add, add(index, obj), remove(index), remove(Object)

Choosing a remove Method

  • Passing an int calls remove(int index) — removes by position.
  • Passing an Integer (for example, Integer.valueOf(n)) calls remove(Object obj) — removes by value.
  • For ArrayList<String> or any non-numeric type, remove(someString) always calls remove(Object obj) because there is no int overload to conflict with.

4. Code Examples

A. Fixed Size vs. Growing Size

Run the cell below, then answer the questions that follow.

int[] fixedScores = new int[3];
ArrayList<Integer> growingScores = new ArrayList<Integer>();

System.out.println("fixedScores.length = " + fixedScores.length);
System.out.println("growingScores.size() = " + growingScores.size());

  1. How many values can fixedScores ever hold?
  2. How many values can growingScores hold right now? How many can it hold after more code runs?
  3. Which variable’s number of stored values can change while the program runs?
Check your reasoning
  1. Exactly 3. An array’s length is fixed once it is created.
  2. growingScores holds 0 values right now. It can hold more values later because elements can be added one at a time.
  3. growingScores. An ArrayList grows or shrinks as elements are added or removed; an array’s length never changes.

B. Declaring and Adding Elements

Method call What it does
add(obj) Appends obj to the end of the list
add(index, obj) Inserts obj at index, shifting later elements one position to the right

ArrayList<String> stores String references. ArrayList<Integer> stores Integer references, boxing primitive int values automatically. There is no ArrayList<int>.

Predict: After the three add calls below run, what will playlist contain, in order? Then run the cell to check.

ArrayList<String> playlist = new ArrayList<String>();
playlist.add("Morning Run");
playlist.add("Study Beats");
playlist.add(1, "Focus Mix");

System.out.println(playlist);

Check your reasoning

["Morning Run", "Focus Mix", "Study Beats"]

The first add appends "Morning Run" at index 0. The second add appends "Study Beats" at index 1. The third add inserts "Focus Mix" at index 1, pushing "Study Beats" to index 2.

C. Reading and Changing Elements: get and set

Method call Returns Effect on the list
get(index) The element at index Unchanged
set(index, obj) The element previously at index Replaces that element with obj

Predict: What is first? What will scores contain after the set call? Then run the cell.

ArrayList<Integer> scores = new ArrayList<Integer>();
scores.add(70);
scores.add(85);
scores.add(90);

int first = scores.get(0);
scores.set(1, 95);

System.out.println("first = " + first);
System.out.println("scores = " + scores);

Check your reasoning

first is 70. get reads a value without removing or changing anything.

After set(1, 95), scores holds [70, 95, 90]. set replaces the value at index 1; the list keeps the same number of elements.

Watch the boundary: a valid index for get and set runs from 0 to size() - 1, the same rule as array indexing. Run the cell below and read the error Java reports.

ArrayList<Integer> boundaryScores = new ArrayList<Integer>();
boundaryScores.add(70);
boundaryScores.add(85);
boundaryScores.add(90);

boundaryScores.get(3);

get(3) throws IndexOutOfBoundsException because boundaryScores only has valid indexes 0, 1, and 2. set(3, value) fails the same way. Neither method can create a new element at an index that does not exist yet; only add does that.

D. size() and Traversal

Arrays report their length with the length field. ArrayList reports its length with the size() method. There is no length field on an ArrayList.

Predict: What does this print? Then run the cell.

ArrayList<String> tasks = new ArrayList<String>();
tasks.add("Read");
tasks.add("Write code");
tasks.add("Test");

for (int i = 0; i < tasks.size(); i++) {
    System.out.println(i + ": " + tasks.get(i));
}

Pause: Why does the loop use tasks.size() instead of a fixed number like 3?

Check your reasoning

Using tasks.size() keeps the loop correct even if elements are added or removed before it runs. A fixed number would need to be rewritten by hand every time the list’s contents change, and it can fall out of sync with the list.

Find the mistake

Run the cell below and read the compiler error.

ArrayList<String> mistakeTasks = new ArrayList<String>();
mistakeTasks.add("Read");
System.out.println(mistakeTasks.length);

Reveal the repair

mistakeTasks.length fails to compile. ArrayList has no length field. Use mistakeTasks.size() instead.

E. Removing Elements: Two remove Methods

ArrayList has two different remove methods, and they can be confused for ArrayList<Integer>.

Method call Meaning for ArrayList<Integer>
remove(int index) Removes the element at position index
remove(Object obj) Removes the first element equal to obj

Predict: Does values.remove(1) remove the value 1, or the element at index 1? Then run the cell.

ArrayList<Integer> values = new ArrayList<Integer>();
values.add(10);
values.add(20);
values.add(30);

values.remove(1);
System.out.println(values);

Check your reasoning

values becomes [10, 30]. An int argument matches remove(int index), so this removes the element at index 1, which was 20.

To remove the Integer value 1 by value instead of by index, box it first: values.remove(Integer.valueOf(1)). This calls remove(Object obj) because the argument is now an Integer, not an int. Run the cell below to see remove(Object obj) in action, removing a value instead of a position.

ArrayList<Integer> values2 = new ArrayList<Integer>();
values2.add(10);
values2.add(20);
values2.add(30);

values2.remove(Integer.valueOf(20));
System.out.println(values2);

Both remove methods shift every later element one position to the left and reduce size() by one.


5. Hacks & Practice Tasks

Prepare your submission IPYNB

  1. Create a new notebook in your portfolio homework area: _notebooks/homework.
  2. Add one raw cell at the top with the frontmatter:
---
layout: post
codemirror: true
title: ArrayList Methods HW
categories: [Java]
lesson_language: Java
lesson_topic: ArrayList Methods HW
lesson_part: interactive
lesson_type: lesson
permalink: /csa/unit_04/4_8-hw
author: yourGithubID
---
  1. Add code cells for the Popcorn Hack and both parts of the Homework Hack. Make sure every cell runs with visible output.
  2. Submit the link to your published page at the bottom of this page, and paste this in the description box:
Lesson: CSA 4.8 ArrayList Methods
Popcorn: buildCountdown implemented and tested against all three sample calls
Homework Part A: swapFirstAndLast implemented and tested against all three sample calls
Homework Part B: removeFirstOccurrence implemented and tested against all three sample calls

Submission Safety Rules (Read First)

  • One method per cell for the Hacks, ending with a test cell that prints its results.
  • Run each cell and leave the output showing.
  • Use remove(Object obj) deliberately where the contract calls for it; do not just guess which overload runs.
  • Use ## headings or smaller.

Popcorn Hack (In-Class)

Write buildCountdown(int start) that returns a new ArrayList<Integer> containing every integer from start down to 1, in that order.

Contract: start >= 0. If start is 0, return an empty list. Use a loop and add().

Call Expected result
buildCountdown(3) [3, 2, 1]
buildCountdown(1) [1]
buildCountdown(0) []

Write your solution in the cell below, then run the test cell after it.

public static ArrayList<Integer> buildCountdown(int start) {
    // Build and return the countdown list.
    return null;
}

System.out.println(buildCountdown(3)); // expect [3, 2, 1]
System.out.println(buildCountdown(1)); // expect [1]
System.out.println(buildCountdown(0)); // expect []

Reveal a solution after writing yours
public static ArrayList<Integer> buildCountdown(int start) {
    ArrayList<Integer> result = new ArrayList<Integer>();
    for (int i = start; i >= 1; i--) {
        result.add(i);
    }
    return result;
}

Self-check: Does your loop stop correctly so start equal to 0 produces an empty list? Does the list count down instead of up?

Reflect

  • The loop condition I used, and why it stops at the right place:
  • My additional test call and its expected result:

Homework Hack

Part A — swap first and last. Write swapFirstAndLast(ArrayList<Integer> nums) that swaps the values at index 0 and the last index of nums, in place.

Contract: nums contains at least one element. Do not return a new list; modify nums directly. Use get() and set(), and a temporary variable to hold one value during the swap.

Starting list List after the call
[1, 2, 3, 4] [4, 2, 3, 1]
[5] [5]
[7, 9] [9, 7]

Write your solution in the cell below, then run the test cell after it.

public static void swapFirstAndLast(ArrayList<Integer> nums) {
    // Swap the values at index 0 and the last index.
}

ArrayList<Integer> swapTest1 = new ArrayList<Integer>();
swapTest1.add(1); swapTest1.add(2); swapTest1.add(3); swapTest1.add(4);
swapFirstAndLast(swapTest1);
System.out.println(swapTest1); // expect [4, 2, 3, 1]

ArrayList<Integer> swapTest2 = new ArrayList<Integer>();
swapTest2.add(5);
swapFirstAndLast(swapTest2);
System.out.println(swapTest2); // expect [5]

ArrayList<Integer> swapTest3 = new ArrayList<Integer>();
swapTest3.add(7); swapTest3.add(9);
swapFirstAndLast(swapTest3);
System.out.println(swapTest3); // expect [9, 7]

Reveal a solution after writing yours
public static void swapFirstAndLast(ArrayList<Integer> nums) {
    int lastIndex = nums.size() - 1;
    int temp = nums.get(0);
    nums.set(0, nums.get(lastIndex));
    nums.set(lastIndex, temp);
}

Self-check: Did you save the first value in a temporary variable before overwriting it? Does a one-element list stay unchanged?

Reflect

  • Why a temporary variable is necessary here:
  • What would happen if I set index 0 before reading the last value:

Part B — remove by value. Write removeFirstOccurrence(ArrayList<Integer> nums, int target) that removes only the first element equal to target, leaving the rest of the list unchanged. If target is not in the list, leave nums as is.

Contract: Modify nums directly. Use remove(Object obj), not remove(int index).

Starting list target List after the call
[4, 7, 2, 7] 7 [4, 2, 7]
[1, 2, 3] 9 [1, 2, 3]
[5] 5 []

Write your solution in the cell below, then run the test cell after it.

public static void removeFirstOccurrence(ArrayList<Integer> nums, int target) {
    // Remove the first element equal to target, using remove(Object obj).
}

ArrayList<Integer> removeTest1 = new ArrayList<Integer>();
removeTest1.add(4); removeTest1.add(7); removeTest1.add(2); removeTest1.add(7);
removeFirstOccurrence(removeTest1, 7);
System.out.println(removeTest1); // expect [4, 2, 7]

ArrayList<Integer> removeTest2 = new ArrayList<Integer>();
removeTest2.add(1); removeTest2.add(2); removeTest2.add(3);
removeFirstOccurrence(removeTest2, 9);
System.out.println(removeTest2); // expect [1, 2, 3]

ArrayList<Integer> removeTest3 = new ArrayList<Integer>();
removeTest3.add(5);
removeFirstOccurrence(removeTest3, 5);
System.out.println(removeTest3); // expect []

Reveal a solution after writing yours
public static void removeFirstOccurrence(ArrayList<Integer> nums, int target) {
    nums.remove(Integer.valueOf(target));
}

Self-check: Did you box target into an Integer so Java calls remove(Object obj) instead of remove(int index)? What would go wrong if you called nums.remove(target) directly?

Reflect

  • Why boxing target changes which remove method is called:
  • My additional test call and its expected result:

Exit Ticket

  1. What does add(index, obj) do differently from add(obj)?
  2. Why does get(index) never change the size of a list, while remove(index) always does?
  3. For ArrayList<Integer> nums containing [4, 7, 2], what is the difference between nums.remove(1) and nums.remove(Integer.valueOf(1))?
  4. Why does ArrayList use size() instead of a length field?
Exit-ticket key
  1. add(obj) appends to the end. add(index, obj) inserts at a specific position and shifts later elements right.
  2. get only reads a value; it does not add or remove elements. remove deletes an element, so the list holds one fewer value afterward.
  3. nums.remove(1) removes the element at index 1, which is 7, leaving [4, 2]. nums.remove(Integer.valueOf(1)) searches for the value 1 as an Object; since 1 is not in the list, nothing is removed.
  4. size() is a method because the number of elements can change while the program runs; a fixed field like an array’s length would not reflect additions and removals.

6. Grading Plan (1 Point Total)

Part Points What earns the points
Popcorn (buildCountdown) 0.25 Correct output for all three sample calls, including the empty-list case.
Homework Part A (swapFirstAndLast) 0.25 Swaps in place using get/set and a temporary variable; the one-element case stays unchanged.
Homework Part B (removeFirstOccurrence) 0.25 Uses remove(Object obj) (not remove(int index)) and leaves the list unchanged when target is absent.
Code quality and reflection 0.25 Every cell runs with visible output, and the Reflect prompts are answered in the student’s own words.
Total 1.0  

Quick Validation Checklist

  • Every Hack cell runs and prints visible output that matches the expected results.
  • remove(Object obj) is used deliberately, not by accident, in Part B.
  • size() is used instead of length anywhere a list’s element count is needed.
  • All three Reflect prompts are answered.
  • The Exit Ticket questions are answered before submitting.

7. Lesson Revisions & Feedback Evidence

Feedback Received: Lesson authors: what your peers said in the practice run.

Revision Made: Lesson authors: what you changed because of it.


References

College Board. (2025). AP Computer Science A course and exam description [Effective fall 2025]. See Topic 4.8, ArrayList Methods, pp. 110-111.

Submit Assignment

Click to upload or drag and drop
PDF, ZIP, images, documents, or Jupyter notebooks (.ipynb) (Max 10MB per file)

Need to update a submission later? Open the submissions dashboard.