AP CSA Study Guide: Data Collections and Dynamic Arrays

Wrapper Classes: Integer and Double

Unlike standard arrays, an ArrayList cannot directly store primitive data types (like int, double, or boolean). They can only store references to objects. To solve this, Java provides Wrapper Classes which "wrap" a primitive value in an object.

Key Concepts

  • Integer: The wrapper class for int.
  • Double: The wrapper class for double.
  • Auto-boxing: The automatic conversion the Java compiler makes between the primitive types and their corresponding object wrapper classes. For example, converting an int to an Integer.
  • Unboxing: The reverse process—converting an Integer to an int.

Visual representation of Auto-boxing and Unboxing mechanisms

Code Example

// Using raw wrapper classes (Manual)
Integer myIntObj = new Integer(5); // Deprecated in newer Java, but concept remains
int myInt = myIntObj.intValue();   // Manual unboxing

// Auto-boxing (What you actually write)
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(7); // Auto-boxing: 7 (int) becomes new Integer(7)

// Unboxing
int num = numbers.get(0); // Unboxing: Integer object becomes primitive int

The ArrayList Class

The ArrayList is a class in the java.util package that represents a resizable array. Unlike standard arrays, where the size is fixed upon creation, an ArrayList grows and shrinks automatically as you add or remove elements.

Declaration and Initialization

To use an ArrayList, you must import it: import java.util.ArrayList;.

Syntax:
ArrayList<E> listName = new ArrayList<E>();

  • <E>: This is a generic type parameter. It specifies the type of elements the list will hold (e.g., <String>, <Integer>, <Student>).

Essential ArrayList Methods

Below captures the specific methods tested on the AP CSA exam:

Method SignatureDescriptionReturn Value
int size()Returns the number of elements in the list.An integer representing the count.
boolean add(E obj)Appends obj to the end of the list.Always returns true.
void add(int index, E obj)Inserts obj at the specified index. Elements at and to the right of index shift right.void (nothing).
E get(int index)Returns the element at the specified position.The object at that index.
E set(int index, E obj)Replaces the element at index with obj.The OLD element that was replaced.
E remove(int index)Removes the element at index. Elements to the right shift left.The element that was removed.

Note: Accessing an index less than 0 or greater than/equal to size() results in an IndexOutOfBoundsException.

Diagram showing how indices shift during add and remove operations

Shifting Explanation

  • Insertion (add with index): If you have [A, B, C] and call add(1, D), the list becomes [A, D, B, C]. Indices of B and C increase by 1.
  • Deletion (remove): If you have [A, B, C] and call remove(1), the list becomes [A, C]. The index of C decreases by 1.

Traversing ArrayLists

Just like arrays, you need to iterate through ArrayLists to access or modify data. There are two primary ways to do this.

1. Standard for Loop

Use this when you need access to the index (e.g., for replacing elements or complex logic).

ArrayList<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");

for (int i = 0; i < names.size(); i++) {
    // Use .get(i) to access elements
    System.out.println(i + ": " + names.get(i));
}

2. Enhanced for Loop (For-Each)

Use this for simple traversal where you do not need the index and do not intend to modify the structure of the list (add/remove).

for (String n : names) {
    System.out.println(n);
}

Restriction: You cannot use an enhanced for-loop to remove elements or replace elements (modify the reference currently held by the loop variable).


Developing Algorithms Using ArrayLists

Linear Search

Finding if an element exists or finding its location.

public int findTarget(ArrayList<Integer> list, int target) {
    for (int i = 0; i < list.size(); i++) {
        // Use .equals() for objects! Auto-unboxing handles == for Integers mostly,
        // but .equals is safer for generic objects.
        if (list.get(i).equals(target)) {
            return i; // Return index
        }
    }
    return -1; // Not found
}

The "Remove Elements" Trap

A common algorithm is removing all elements that meet a certain condition (e.g., remove all failing grades). This is a frequent source of logic errors.

The Problem: When you remove an element at index i, all subsequent elements shift left. If you then increment i, you skip the element that just shifted into the spot i occupied.

Correct Approach 1: Traverse Backwards
This prevents shifting from affecting indices you haven't checked yet.

// Remove all grades less than 60
for (int i = grades.size() - 1; i >= 0; i--) {
    if (grades.get(i) < 60) {
        grades.remove(i);
    }
}

Correct Approach 2: Conditional Increment
Only increment i if you didn't remove an element.

int i = 0;
while (i < grades.size()) {
    if (grades.get(i) < 60) {
        grades.remove(i); // size shrinks, elements shift, do not increment i
    } else {
        i++;
    }
}

Common Mistakes & Pitfalls

  1. Size vs. Length: Arrays have a .length property. ArrayLists use the .size() method. Mixing these up is a syntax error.
  2. The Return Value Paradox: Students often forget that set(i, obj) and remove(i) return the data that was previously at that index. Exam questions often try to trick you by doing something like: System.out.println(list.set(0, "New"));—this prints the old value, not "New".
  3. Object Comparison: Using == to compare objects (like Strings or Integers outside of the cached range). Always use .equals() for checking content equality.
  4. ConcurrentModificationException: Trying to add or remove items from a list while iterating over it using an enhanced for-loop will crash your program. Always use a standard for-loop for structural modifications.
  5. Index Logic: Forgetting that the last valid index is size() - 1, not size().