How to Solve AP CSA Free Response Questions: A Step-by-Step Strategy

AP CSA FRQ Strategy Exam Prep

How to Solve AP CSA Free Response Questions: A Step-by-Step Strategy

By Tanner Crow — AP Computer Science Teacher & Tutor • 1,845+ Hours Tutored • 451 Five-Star Reviews

Here is what most students get wrong about FRQs: They open the exam, read the question once, and start writing Java code immediately. That approach costs them 3–5 points on nearly every question. The students who score 8–9 out of 9 on FRQs treat each problem like a structured engineering task, not a sprint. This guide teaches you exactly that framework.

What the AP CSA FRQ Section Looks Like

The AP CSA exam dedicates the entire second section to four free-response questions. You get 90 minutes total, which works out to roughly 22 minutes per question. Each FRQ is scored on a rubric worth 9 points. The four question types you will encounter map to the 2025–2026 curriculum units:

FRQ # Question Type Primary Unit Alignment
FRQ 1 Methods and Control Structures Unit 2: Selection & Iteration
FRQ 2 Class Writing Unit 3: Objects & Classes
FRQ 3 Array / ArrayList Unit 4: Data Collections
FRQ 4 2D Array Unit 4: Data Collections

Each question may have two or three parts labeled (a), (b), and sometimes (c). Parts are scored independently. A wrong answer in part (a) does not prevent you from earning full credit in part (b) if you use your part (a) method correctly in part (b), even if that method was incorrect.


Before You Read the Options: Predict First

This principle is not just for multiple-choice questions. It applies to free-response problems too. Before you write a single line of Java, you should already have a mental model of what a correct solution looks like. This is called answer prediction, and it is one of the most powerful habits you can build.

Why this matters: When you start writing code without a plan, you get pulled toward whatever feels syntactically comfortable rather than what actually solves the problem. You write a for-loop because loops feel natural, not because you have confirmed a loop is the right structure. Predicting forces intentional thinking.

The same logic applies when reviewing answer choices on the multiple-choice section. Students who formulate their own answer before reading options are far less likely to be swayed by a convincing but wrong distractor. On the FRQ side, students who sketch a pseudocode plan before writing Java write cleaner, more complete solutions.


The 5-Step FRQ Framework

1
Read the Entire Problem Once — Actively

Read the full question from top to bottom before touching your answer sheet. As you read, physically underline or circle these four things:

  • The return type of every method you must write
  • Parameter names and their types
  • Methods already provided that you are allowed to call
  • Edge cases or special conditions mentioned in the problem description
Watch for these key words: "not," "except," "always," "never," "at least," "exactly," "precondition guarantees." These words narrow what your code must handle and are frequently the difference between a 7 and a 9.
2
Identify the FRQ Type and What Pattern It Requires

Once you know the question type, you know the pattern. Experienced test-takers recognize these instantly:

  • Methods & Control Structures: You are completing one or two methods. Look for a for/while loop opportunity and a conditional inside it.
  • Class Writing: You are writing constructors, instance variables, and methods. Always declare private instance variables. Always write a full constructor. Return the correct type from each method.
  • Array / ArrayList: You are traversing and either accumulating, filtering, or restructuring. Identify whether you need an index-based for-loop, a for-each loop, or ArrayList methods like add(), remove(), and get().
  • 2D Array: You need a nested loop. Outer loop = rows, inner loop = columns, unless specified otherwise.
3
Predict and Plan Before Writing Java

Spend 2–3 minutes writing pseudocode or annotated English in the margin. Your plan should answer:

  • What data structure am I working with?
  • What loop type do I need and what are the bounds?
  • What is the condition for the branch inside the loop?
  • What do I accumulate, return, or modify?
  • Which provided methods should I call, and where?
Pro tip from tutoring 450+ students: If you cannot write pseudocode, you do not understand the problem yet. Do not start writing Java until you can state the algorithm in plain English. Students who skip this step are the ones who cross things out and run out of time.
4
Write Java Incrementally — One Rubric Point at a Time

FRQ rubrics award points for specific, identifiable pieces of logic. Write code with those checkpoints in mind. Leave space between lines in case you need to insert something. Common rubric checkpoints include:

  • Correct method header (matches the signature given)
  • Loop with correct bounds
  • Correct access of array elements or ArrayList elements inside the loop
  • Correct conditional logic
  • Correct return statement with the right type

Each checkpoint is worth a point. You do not have to write perfect, elegant code. You need to hit the rubric checkpoints. Incomplete code that hits 6 checkpoints earns 6 points. Elegant code that misses a return type earns less.

5
"Slash the Trash" — Eliminate and Verify

With 3 minutes remaining for the question, audit your code against the problem:

  • Trace through the provided examples and verify your output matches
  • Check for off-by-one errors at loop boundaries
  • Confirm every method you were told to write actually has a return statement
  • Confirm you used the provided helper methods where the question expected them
  • Remove any code that has unintended side effects (printing to output when not asked, modifying a parameter you were not supposed to modify)

Full Worked Example: Applying the Framework

Let us apply all five steps to a representative FRQ prompt. This is an original practice problem modeled on the FRQ 3 (Array / ArrayList) style.

Scenario: The ScoreTracker class manages a list of integer scores from a quiz. You will write two methods for this class.

Method headers provided:
public int countAbove(int threshold)
public void removeBelow(int cutoff)

Instance variable: private ArrayList<Integer> scores; (already initialized)

(a) Write the countAbove method. It should return the number of elements in scores that are strictly greater than threshold.

(b) Write the removeBelow method. It should remove all elements from scores that are strictly less than cutoff.

Step 1 — Read Actively

Underline: return type int (part a), void (part b), parameter threshold, parameter cutoff, "strictly greater than," "strictly less than," instance variable scores is an ArrayList.

Step 2 — Identify the Pattern

FRQ 3 / ArrayList. Part (a) is a counting pattern — traverse and accumulate. Part (b) is a removal pattern — traverse backwards or use an iterator to safely remove during traversal.

Critical trap in part (b): If you traverse forwards with a standard index-based for-loop and call remove(), you will skip elements immediately after a removal because the indices shift. You must traverse backwards (from size − 1 down to 0) or use an iterator. The AP readers know this trap and the rubric rewards handling it correctly.

Step 3 — Predict the Plan

Part (a): Initialize a counter to 0. Loop through scores. If current score > threshold, increment counter. Return counter.

Part (b): Loop from the last index down to 0. If current score < cutoff, call scores.remove(i).

Step 4 — Write the Java

Things to lock in before writing a single line:
Return type is int — you need a counter variable.
You are not removing anything, so a for-each loop is safe.
The condition is strictly greater-than (not greater-than-or-equal).
The method must have an explicit return count; at the end.

If you had all four of those before reading the solution below, you were ready to write it without looking.
Part (a) — countAbove
public int countAbove(int threshold) {
    int count = 0;                           // accumulator
    for (int score : scores) {              // for-each is safe here (no removal)
        if (score > threshold) {
            count++;
        }
    }
    return count;
}
The single biggest question to answer before writing this method:
If you remove an element at index i while traversing forward, the element at index i+1 silently shifts into position i and is never examined. Consecutive targets will be partially skipped.

Two valid fixes — pick one and commit:
1. Traverse backwards: start at scores.size() - 1, decrement to 0. Removals only affect indices above the current position, which you have already passed.
2. Traverse forward but add i-- immediately after each remove(i) call so the index stays at the same position next iteration.

If you identified the trap and chose an approach before looking, you already understand the hardest part of this problem.
Part (b) — removeBelow (critical: traverse backwards)
public void removeBelow(int cutoff) {
    for (int i = scores.size() - 1; i >= 0; i--) {  // backwards traversal
        if (scores.get(i) < cutoff) {
            scores.remove(i);                          // index-based remove
        }
    }
}

Step 5 — Verify

Trace with scores = [85, 42, 91, 60, 38], threshold = 70, cutoff = 50:

Work through this mentally first. For countAbove(70), how many elements in the list are strictly greater than 70? Write your number down. For removeBelow(50), which elements are strictly less than 50? What does the final list look like after they are removed?

Once you have your prediction, expand the trace below to check.

countAbove(70): 85 > 70 (count=1), 42 ≤ 70, 91 > 70 (count=2), 60 ≤ 70, 38 ≤ 70. Returns 2. Correct.

removeBelow(50): i=4: 38 < 50, remove. List=[85,42,91,60]. i=3: 60 ≥ 50, keep. i=2: 91 ≥ 50, keep. i=1: 42 < 50, remove. List=[85,91,60]. i=0: 85 ≥ 50, keep. Final list=[85,91,60]. Correct.


How Rubric Points Are Awarded

The College Board rubric for FRQ 3 typically awards one point each for: correct loop structure, correct ArrayList access inside the loop, correct conditional, correct accumulator or modification, and correct return value. For a removal question, an additional point is awarded specifically for a traversal method that correctly handles index shifting. That is the backwards-traversal point, and it is one of the most commonly missed.

Penalty-free errors: Missing semicolons where the intent is clear, spelling differences in identifiers when unambiguous, using length vs .length() or .size() where context is obvious. You are not penalized for these. Focus on logic, not perfect syntax.

The 4 Most Costly FRQ Mistakes

After reviewing hundreds of student FRQ submissions — both in class and through AP CSA tutoring sessions — the same four errors appear on nearly every score report in the 5–7 range. Fixing just these four moves most students into the 8–9 range.

1. Not calling the provided methods. The question gives you helper methods for a reason. If you reimplement the logic manually instead of calling the provided method, you may still get the logic point but lose the method-call point. Read the class interface carefully and use what is given.

2. Writing code that only solves the example. The rubric tests general logic. Hard-coding values that work on the example input but fail on a general case gets zero credit for that rubric point.

3. Forgetting the return statement. This is the most common 8-out-of-9 mistake. A void method that accidentally has a return statement is a penalty. A non-void method missing its return statement misses the return-value rubric point. Always check.

4. Forwards traversal with ArrayList removal. Covered above. This costs the traversal correctness point, which is often worth 1–2 points on ArrayList removal questions.


Practice: Test Your FRQ Strategy Knowledge

Before reading the answer choices, predict what you think is wrong or correct. Then select your answer and check your reasoning.

Question 1 — Spot the Error
A student writes the following method intended to remove all occurrences of a target value from an ArrayList of integers. Which line contains the error that causes incorrect behavior?
public void removeAll(ArrayList<Integer> list, int target) {
    for (int i = 0; i < list.size(); i++) {    // Line 1
        if (list.get(i) == target) {            // Line 2
            list.remove(i);                     // Line 3
        }                                       // Line 4
    }
}
Look at the loop and the remove call. What happens to the indices of remaining elements each time an element is deleted? Does the loop counter account for that shift? Form your answer, then select an option below.
  • (A) Line 1, because i < list.size() does not account for an empty list
  • (B) Lines 1 and 3 together, because removing an element at index i shifts subsequent elements left, so the element immediately after each removed value is skipped
  • (C) Line 2, because == cannot compare Integer objects for value equality when values exceed 127
  • (D) Line 3, because ArrayList.remove(int index) should be replaced with ArrayList.remove(Integer.valueOf(target)) on every iteration
Correct Answer: (B)

The error is the interaction between Lines 1 and 3. When remove(i) is called, all elements after index i shift left by one position. On the next iteration, i increments, but the element that shifted into index i has never been examined. If two consecutive target values appear in the list, only the first is removed. The fix is to decrement i after removal (i--) or traverse backwards from list.size() - 1 down to 0. Option (C) is a plausible distractor because == on boxed Integers is unreliable above 127, but on this exam target is passed as a primitive int and auto-unboxing makes == reliable here. Option (D) would be an alternative approach but is not the primary error causing skipped elements.
Question 2 — I, II, III Analysis
Consider the following incomplete method from a class that has a private int[] field named data:
public int findMax() {
    int max = 0;
    for (int i = 0; i < data.length; i++) {
        if (data[i] > max) {
            max = data[i];
        }
    }
    return max;
}
Which of the following statements identify a real defect in this method?

I. The method returns 0 instead of the correct maximum when all values in data are negative.
II. The method throws an ArrayIndexOutOfBoundsException when data has exactly one element.
III. Initializing max to data[0] instead of 0 would eliminate the defect without introducing new errors, provided data is guaranteed non-empty.
For Statement I: try the array [-5, -3, -9] mentally. What does max = 0 return vs. the true maximum?
For Statement II: trace the loop when data.length == 1. Does i ever reach an out-of-bounds index?
For Statement III: if data[0] is the starting value, does any all-negative array still fool the method?
Decide true/false for each, then select below.
  • (A) I only
  • (B) II only
  • (C) I and III only
  • (D) I, II, and III
Correct Answer: (C) — I and III only

Statement I is TRUE. Initializing max = 0 means any array containing only negative values (e.g., [-5, -3, -9]) will return 0, which is incorrect because 0 is not in the array. This is a genuine defect.

Statement II is FALSE. When data.length is 1, the loop runs from i = 0 to i < 1, so i = 0 executes exactly once and no out-of-bounds access occurs. There is no exception.

Statement III is TRUE. Initializing max = data[0] corrects the all-negative defect because the starting sentinel is guaranteed to be an actual value in the array. As long as the precondition states data is non-empty, this fix is valid.
Question 3 — Predict the Output
A student is writing FRQ 2 (Class Writing) and produces the following class. Before reading the options, predict what the constructor does to the instance variable value.
public class Counter {
    private int value;

    public Counter(int value) {
        value = value;                   // intended to initialize instance variable
    }

    public int getValue() {
        return value;
    }
}
What does a call to new Counter(10).getValue() return?
In the constructor body, there are two things both named value: the parameter and the instance variable. When they share a name, which one does Java use on each side of the assignment? Does the instance variable ever get updated? What is its default value if it is never set? Form your answer before selecting below.
  • (A) 0, because the assignment value = value assigns the parameter to itself and the instance variable is never set, defaulting to 0
  • (B) 10, because Java resolves the left-hand value to the instance variable and the right-hand value to the parameter
  • (C) A compile-time error, because a local variable and an instance variable cannot share the same name
  • (D) An unpredictable value, because the behavior of value = value is undefined when names conflict
Correct Answer: (A)

This is one of the most frequently tested "spot the bug" scenarios on FRQ 2. When a constructor parameter has the same name as an instance variable, the parameter shadows the instance variable inside that method. The line value = value assigns the parameter to itself, which is a no-op. The instance variable this.value is never touched, so it retains its default value of 0. The correct fix is this.value = value;. Java does not produce a compile-time error for this code, which is why it is such a dangerous mistake to make on the exam.
Question 4 — FRQ Strategy: Which Approach Earns More Rubric Points?
A student is writing part (b) of an FRQ. Part (b) requires calling the isValid method written in part (a), but the student's part (a) solution has a logic error. The student knows part (a) is wrong. Which of the following approaches is most likely to maximize their total score across both parts?

I. Rewrite part (a) from scratch to fix the logic error, then write part (b) calling the corrected version.
II. Leave part (a) as-is. In part (b), call isValid exactly as the rubric expects, even though the student knows it is incorrect.
III. Skip part (a) entirely and write only part (b), defining an inline version of the helper logic directly inside part (b).
Think about what "parts are scored independently" actually means on the rubric. If the rubric for part (b) has a bullet for "calls isValid correctly," does it matter whether isValid itself is correct? What about option III — if the rubric expects a method call and you bypass it with inline logic, what happens to that point? Commit to an answer, then select below.
  • (A) I only, because a correct part (a) is required to earn any credit in part (b)
  • (B) I or II depending on the time remaining; II is valid because part (b) is scored independently, and calling isValid correctly earns the method-call point regardless of whether part (a) is correct
  • (C) III only, because the reader cannot penalize a solution that produces correct output
  • (D) II only, because attempting to fix part (a) risks introducing new errors that could reduce the part (a) score further
Correct Answer: (B)

This is a critical exam-day strategy point. AP CSA FRQ rubrics explicitly state that parts are scored independently. Even if part (a) earns 0 points due to a logic error, part (b) can still earn full credit if it calls isValid appropriately and implements the correct surrounding logic. If you have time remaining, attempt to fix part (a) because that maximizes your potential points across both parts. If you are running short on time, move to part (b) and call the method as the rubric expects — you will still earn the method-call point. Option (C) is tempting but risky: reimplementing logic inline when the rubric expects a method call often loses the method-call point on the rubric, even if the output would be correct.

Keep Practicing With Real FRQs

The fastest way to internalize this framework is to apply it to official College Board questions from previous exams. Every study guide below is aligned to the 2025–2026 4-unit curriculum.

📚

Want to walk through FRQs with someone who has done this 1,800+ times?

If you are hitting a wall on a specific FRQ type or just want guided practice before the exam, one-on-one AP CSA tutoring sessions are available. Sessions focus on exactly the kind of structured problem-solving covered in this guide — no busywork, no re-teaching things you already know. Most students see meaningful improvement in FRQ scores within two or three sessions.

Learn About Tutoring
About the Author: Tanner Crow is an AP Computer Science teacher at Blue Valley North High School with over 11 years of classroom experience and 1,845+ verified tutoring hours on Wyzant (451 reviews, 5.0 rating). His AP CSA students score 5s at more than twice the national rate: 54.5% vs. 25.5% globally. The strategies in this guide are the same ones used in his classroom and in private AP CSA tutoring sessions every week. He built APCSExamPrep.com so every student has access to them for free.
Back to blog

Leave a comment

Please note, comments need to be approved before they are published.