AP CS A AP CSP Tutoring Blog Request a Session
← Back to Blog
AP CS A

AP CS A Practice Problems with Solutions

By Namrata Poladia April 25, 2026

The best way to prepare for the AP CS A exam is to practice writing and tracing Java code under conditions that resemble the real test. This set of problems covers the topics most heavily tested: loop and conditional tracing, arrays, ArrayLists, classes, and recursion. The MCQ problems mirror the format of the multiple-choice section; the FRQ problems mirror the free-response section.

How to use this guide: attempt each problem before reading the solution. For MCQ problems, cover the answer and trace the code by hand. For FRQ problems, write your solution on paper before comparing it to the model answer. Reading solutions without attempting the problems first provides little benefit.


Part 1: Multiple Choice Practice

Each problem below mirrors the format of the AP CS A MCQ section. Trace carefully, write down variable values, and don't guess.

Problem 1: Loop Tracing

What is printed when the following code runs?

int x = 10;
int count = 0;
while (x > 0) {
    if (x % 3 == 0) {
        count++;
    }
    x -= 2;
}
System.out.println(count);

(A) 0    (B) 1    (C) 2    (D) 3    (E) 5

Show Answer and Explanation

Answer: (B) 1

Trace the loop, tracking x and count:

x (start of iteration)x % 3 == 0?countx after x -= 2
1010 % 3 = 1, No08
88 % 3 = 2, No06
66 % 3 = 0, Yes14
44 % 3 = 1, No12
22 % 3 = 2, No10
0Loop ends (0 > 0 is false)1

Only x = 6 is divisible by 3 in this sequence. Output: 1.

Problem 2: String Methods

What is printed when the following code runs?

String s = "computer";
System.out.println(s.substring(3, 6).toUpperCase());

(A) COM    (B) put    (C) PUT    (D) MPU    (E) ute

Show Answer and Explanation

Answer: (C) PUT

substring(3, 6) returns characters at indices 3, 4, and 5 (the end index is exclusive). The string "computer" has these indices:

Index01234567
Charcomputer

Indices 3–5 give "put". After .toUpperCase(), the result is "PUT".

Problem 3: Array Traversal

What is printed when the following code runs?

int[] arr = {4, 7, 2, 9, 1, 5};
int result = arr[0];
for (int i = 1; i < arr.length; i++) {
    if (arr[i] > result) {
        result = arr[i];
    }
}
System.out.println(result);

(A) 4    (B) 5    (C) 7    (D) 9    (E) 28

Show Answer and Explanation

Answer: (D) 9

This is a standard maximum-finding algorithm. result starts at arr[0] = 4. The loop checks each subsequent element: 7 > 4 so result becomes 7; 2 is not > 7; 9 > 7 so result becomes 9; 1 is not > 9; 5 is not > 9. Final value of result is 9. Note that (E) 28 would be the sum, not the maximum.

Problem 4: Recursion Tracing

What value does mystery(6) return?

public static int mystery(int n) {
    if (n <= 0) {
        return 0;
    }
    return n + mystery(n - 2);
}

(A) 6    (B) 8    (C) 10    (D) 12    (E) 21

Show Answer and Explanation

Answer: (D) 12

Trace the call stack:

mystery(6)  → 6 + mystery(4)
  mystery(4)  → 4 + mystery(2)
    mystery(2)  → 2 + mystery(0)
      mystery(0)  → 0  (base case: 0 <= 0)
    mystery(2)  → 2 + 0 = 2
  mystery(4)  → 4 + 2 = 6
mystery(6)  → 6 + 6 = 12

The method sums all even positive integers from 2 up to n (when n is even): 6 + 4 + 2 = 12. Note that (E) 21 would be 1+2+3+4+5+6, which is what the method would return if it decremented by 1 instead of 2.

Problem 5: ArrayList Removal Bug

What does the following code print?

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(7);
list.add(2);
list.add(8);
list.add(1);

for (int i = 0; i < list.size(); i++) {
    if (list.get(i) % 2 == 0) {
        list.remove(i);
    }
}
System.out.println(list);

(A) [3, 7, 1]    (B) [3, 7, 8, 1]    (C) [3, 7, 2, 8, 1]    (D) [2, 8]    (E) [3, 7]

Show Answer and Explanation

Answer: (B) [3, 7, 8, 1]

This problem tests the classic ArrayList removal bug. Trace carefully:

  • i=0: list.get(0) = 3, odd, skip. i becomes 1.
  • i=1: list.get(1) = 7, odd, skip. i becomes 2.
  • i=2: list.get(2) = 2, even, remove. List is now [3, 7, 8, 1]. The 8 shifts from index 3 to index 2. i becomes 3.
  • i=3: list.get(3) = 1, odd, skip. i becomes 4.
  • i=4: list.size() = 4, loop ends.

After removing 2 at index 2, the 8 shifted into index 2. Then i incremented to 3, skipping index 2 entirely. The 8 was never checked. The correct approach is to iterate backwards or decrement i after each removal. The answer (A) [3, 7, 1] is what you'd get with a correct implementation.

Problem 6: Polymorphism

What is printed when the following code runs?

public class Shape {
    public String describe() {
        return "I am a " + getType();
    }
    public String getType() {
        return "shape";
    }
}

public class Circle extends Shape {
    public String getType() {
        return "circle";
    }
}

Shape s = new Circle();
System.out.println(s.describe());

(A) I am a shape    (B) I am a circle    (C) I am a Shape    (D) Compile error    (E) Runtime error

Show Answer and Explanation

Answer: (B) I am a circle

s is declared as type Shape but actually holds a Circle object. When s.describe() is called, Java uses Shape's version of describe() (since Circle doesn't override it). But inside describe(), the call to getType() is resolved at runtime based on the actual object type, which is Circle. So Circle's getType() runs, returning "circle". This is polymorphism: the declared type determines which methods are accessible; the actual type determines which version runs.

There is no compile error because describe() is defined in Shape, which is the declared type. There is no runtime error because Circle is a valid Shape.


Part 2: Free Response Practice

Each FRQ problem below matches the format of one of the four question types on the AP CS A exam. Attempt each on paper before reading the solution. Aim to complete each part in about 20 minutes.

FRQ 1: Methods and Control Structures

Write a static method countInRange that takes an array of integers arr, an integer low, and an integer high (both inclusive), and returns the count of elements in arr whose values are between low and high, inclusive.

For example:

  • countInRange(new int[]{3, 8, 1, 6, 9, 4}, 4, 8) returns 3 (the values 8, 6, and 4 are in range).
  • countInRange(new int[]{3, 8, 1, 6, 9, 4}, 10, 20) returns 0.

Complete the method below:

public static int countInRange(int[] arr, int low, int high) {
    // your code here
}
Show Solution
public static int countInRange(int[] arr, int low, int high) {
    int count = 0;
    for (int val : arr) {
        if (val >= low && val <= high) {
            count++;
        }
    }
    return count;
}

Scoring notes:

  • Initialize count to 0 before the loop. Declaring it without initialization is a compile error.
  • Use >= and <=, not > and <. The problem says "inclusive" on both ends.
  • Use && to require both conditions to be true simultaneously.
  • Return count after the loop, not inside it.
  • An enhanced for loop is appropriate here since you only need values, not indices.

Common mistakes: using || instead of && (returns count of values outside the range instead), returning inside the loop (returns too early), or forgetting to initialize count.

FRQ 2: Writing a Class

Write a class Student that represents a student with a name, a grade level (integer 9–12), and a GPA (double). Your class must include:

  • A constructor that takes a name, grade level, and GPA.
  • Accessor methods getName(), getGrade(), and getGPA().
  • A method isHonorRoll() that returns true if the student's GPA is 3.5 or above, false otherwise.
  • A method promote() that increases the student's grade level by 1. If the grade is already 12, the grade should not change.
  • A toString() method that returns a String in the format: "[Name], Grade [grade], GPA: [gpa]". For example: "Alice, Grade 11, GPA: 3.8".
Show Solution
public class Student {
    private String name;
    private int grade;
    private double gpa;

    public Student(String name, int grade, double gpa) {
        this.name = name;
        this.grade = grade;
        this.gpa = gpa;
    }

    public String getName() {
        return name;
    }

    public int getGrade() {
        return grade;
    }

    public double getGPA() {
        return gpa;
    }

    public boolean isHonorRoll() {
        return gpa >= 3.5;
    }

    public void promote() {
        if (grade < 12) {
            grade++;
        }
    }

    public String toString() {
        return name + ", Grade " + grade + ", GPA: " + gpa;
    }
}

Scoring notes:

  • Instance variables should be private. Using public instance variables is a style error that may cost points on the real exam.
  • The constructor does not have a return type, not even void.
  • isHonorRoll() should return a boolean expression directly: return gpa >= 3.5; is cleaner than an if/else that returns true or false.
  • promote() is a void method; it modifies grade in place. The boundary check (grade < 12) prevents going above 12.
  • toString() uses string concatenation to build the required format. Make sure the format matches exactly.

FRQ 3: ArrayList Manipulation

Write a static method removeDuplicates that takes an ArrayList<Integer> and removes all duplicate values from it, keeping only the first occurrence of each value. The method modifies the list in place and does not return anything.

For example, if the list contains [3, 7, 3, 1, 7, 9, 1], after calling the method it should contain [3, 7, 1, 9].

public static void removeDuplicates(ArrayList<Integer> list) {
    // your code here
}
Show Solution
public static void removeDuplicates(ArrayList<Integer> list) {
    for (int i = list.size() - 1; i >= 1; i--) {
        for (int j = 0; j < i; j++) {
            if (list.get(i).equals(list.get(j))) {
                list.remove(i);
                break;
            }
        }
    }
}

How it works: the outer loop iterates backwards from the last element to index 1. For each element at index i, the inner loop checks whether the same value appears anywhere before it (at indices 0 through i−1). If a match is found, the element at index i is a duplicate and is removed. The break exits the inner loop immediately after removal, since there's no point checking further. Iterating backwards means that removing an element at index i doesn't affect the indices of earlier elements (0 through i−1), which the inner loop still needs to access.

Scoring notes:

  • Use .equals(), not ==, to compare Integer objects. == checks object identity, not value equality, and will fail for values outside the cached range of −128 to 127.
  • The return type is void. Do not add a return statement with a value.
  • The backwards traversal is essential for correctness. A forward traversal with removal causes index-skipping bugs.

FRQ 4: Recursion

Write a recursive method sumArray that computes and returns the sum of all elements in an integer array. The method takes the array and a starting index as parameters. You may not use a loop.

For example, sumArray(new int[]{3, 7, 2, 5}, 0) returns 17.

public static int sumArray(int[] arr, int index) {
    // your code here
}
Show Solution
public static int sumArray(int[] arr, int index) {
    if (index == arr.length) {   // base case: ran past the end
        return 0;
    }
    return arr[index] + sumArray(arr, index + 1); // recursive case
}

Call stack for sumArray({3, 7, 2, 5}, 0):

sumArray(arr, 0)  → 3 + sumArray(arr, 1)
  sumArray(arr, 1)  → 7 + sumArray(arr, 2)
    sumArray(arr, 2)  → 2 + sumArray(arr, 3)
      sumArray(arr, 3)  → 5 + sumArray(arr, 4)
        sumArray(arr, 4)  → 0  (base case: 4 == arr.length)
      sumArray(arr, 3)  → 5 + 0 = 5
    sumArray(arr, 2)  → 2 + 5 = 7
  sumArray(arr, 1)  → 7 + 7 = 14
sumArray(arr, 0)  → 3 + 14 = 17

Scoring notes:

  • The base case is index == arr.length, not index == arr.length - 1. When index equals the length, you've gone past the last valid element (last valid index is arr.length - 1). Returning 0 at this point correctly adds nothing.
  • Each recursive call passes index + 1, moving one step closer to the base case every time.
  • The problem says you may not use a loop, which is a hint that a recursive solution is expected. On the real exam, if recursion is required, using a loop will not earn credit for the recursive logic.

How to Score Your FRQ Responses

The College Board scores FRQs using a rubric that awards points for specific elements, not overall correctness. A method that almost works can still earn most of the points. Here's how to self-assess:

FRQ Element Points Typically Awarded
Correct method signature (name, parameters, return type)1
Correct loop or traversal structure1
Correct conditional logic1
Correct accumulation or result tracking1
Correct return value1

When grading your own work, check each element independently. If your loop is correct but you return the wrong variable, you lose the return point but keep the loop point. Understanding how partial credit works encourages you to write something for every part, even when you're not sure of the complete solution.

What to Do Next

If you got all six MCQ problems correct on the first try: your tracing skills are strong. Spend your remaining prep time on FRQ writing speed and accuracy.

If you missed one or two MCQ problems: review the specific topic you missed. The solutions above explain exactly where the reasoning breaks down. Re-trace the problems you got wrong until the correct answer is obvious, not just memorized.

If you missed three or more: go back to fundamentals for those topics before doing more practice problems. Doing problems without the underlying understanding in place tends to reinforce bad habits rather than correct them.

For FRQs, compare your code to the model solution line by line. If the logic is correct but the syntax is slightly off (missing semicolons, wrong method names), practice writing Java from memory daily. If the logic itself is wrong, trace through what your code actually does versus what the problem asks for, and identify where your mental model broke down.

Want More Practice with Feedback?

Working through practice problems on your own is valuable, but it has limits: you can't always tell why your solution doesn't earn full credit without knowing how the rubric works. ExamReadyUSA's 4-week AP CS A Crash Course includes multiple graded FRQ sessions where Namrata Poladia scores your code using actual AP rubrics and gives you specific feedback on what to fix. Groups are capped at 5 students and every session includes time to ask questions.