0% of the question bank attempted

Compiling and Running Java

Java source code (.java) is compiled by javac into bytecode (.class), which the JVM executes, making Java platform-independent.
  • public class Main { public static void main(String[] args) { } } is the required entry point.
  • Every .java file's public class name must match the filename exactly (Main.java -> class Main).
  • javac Main.java produces Main.class; java Main runs it via the JVM.
  • Java is statically typed: every variable's type is declared and checked at compile time.
  • A missing semicolon or unmatched brace causes a compile-time error, not a runtime error.

Primitive Types: int and double

AP CSA uses int for whole numbers and double for decimal (floating-point) numbers as the two primary numeric types.
  • int stores 32-bit whole numbers, e.g. int x = 5;
  • double stores double-precision decimals, e.g. double pi = 3.14159;
  • Integer division truncates: 7 / 2 evaluates to 3, not 3.5.
  • Mixing types promotes to the wider type: 7 / 2.0 evaluates to 3.5.
  • Casting: (double) 7 / 2 gives 3.5; (int) 3.9 gives 3 (truncates, does not round).
  • The modulus operator % returns the remainder: 7 % 2 is 1.

Variables, Declarations, and Assignment

A variable must be declared with a type before use, and assignment stores a value into that variable's memory location.
  • Declaration: int score; Assignment: score = 90; Combined: int score = 90;
  • Variable names are case-sensitive and conventionally use camelCase (totalScore, not TotalScore).
  • Compound assignment operators: x += 5 means x = x + 5; also -=, *=, /=, %=.
  • Increment/decrement: x++ and x-- change a variable by 1.
  • boolean stores only true or false and is used for logical conditions.
  • String is not primitive; it's a reference type representing text, e.g. String name = "Ada";

String Basics

String objects represent immutable sequences of characters and support several key methods tested on the AP exam.
  • Concatenation with + joins strings: "Hi" + "there" produces "Hithere".
  • str.length() returns the number of characters, e.g. "hello".length() is 5.
  • str.substring(a, b) returns characters from index a up to (not including) b.
  • str.charAt(i) returns the character at index i (0-indexed).
  • str.equals(other) checks value equality; == checks reference equality (a common trap).
  • str.indexOf("x") returns the index of the first occurrence, or -1 if not found.

Expressions and Operator Precedence

Java evaluates expressions following a strict order of operations, similar to standard math precedence rules.
  • Parentheses first, then unary (-, ++, --), then *, /, %, then +, -, then relational, then logical.
  • * / % have equal precedence and evaluate left to right: 8 / 4 * 2 = 4, not 1.
  • Operator precedence determines order but associativity determines direction for equal-precedence ops.
  • System.out.println(2 + 3 + "4") prints "54" because 2+3 evaluates first, then concatenates with "4".
  • System.out.println("4" + 2 + 3) prints "423" because left-to-right string concatenation happens first.

Wrapper Classes and Integer Overflow

Java provides wrapper classes like Integer and Double to treat primitives as objects, and ints have a fixed range that can overflow.
  • Integer.MAX_VALUE is 2147483647; adding 1 to it overflows to Integer.MIN_VALUE (a wraparound bug).
  • Autoboxing automatically converts int to Integer and back when needed, e.g. in ArrayList<Integer>.
  • Double.parseDouble("3.14") and Integer.parseInt("42") convert Strings to numeric types.
  • Math.pow(base, exp), Math.sqrt(x), and Math.abs(x) are common static Math class methods.
  • Math.random() returns a double in [0.0, 1.0); (int)(Math.random() * n) gives a random int in [0, n).
Using == to compare Strings, not .equals() — == checks if two references point to the same object.
Expecting 5 / 2 to equal 2.5, not 2 — integer division truncates the decimal part entirely.
Forgetting that (int) casting truncates toward zero, not rounds — (int) 4.9 is 4, not 5.
Confusing = (assignment) with == (equality comparison) inside conditions.

Classes as Blueprints

A class defines the instance variables (state) and methods (behavior) that every object created from it will have.
  • Instance variables are declared inside the class but outside any method, typically private.
  • private restricts access to within the class only, enforcing encapsulation.
  • An object is a specific instance of a class, created with the new keyword.
  • class Dog { private String name; private int age; } defines a Dog blueprint with two fields.
  • Each object has its own copy of instance variables, independent of other objects of the same class.

Constructors

A constructor initializes a new object's instance variables and shares its name with the class.
  • public Dog(String n, int a) { name = n; age = a; } is a constructor for class Dog.
  • Constructors have no return type, not even void.
  • The keyword this refers to the current object, e.g. this.name = name; resolves naming conflicts with parameters.
  • If no constructor is written, Java provides a default no-argument constructor automatically.
  • You can overload constructors: multiple constructors with different parameter lists in the same class.

Accessor and Mutator Methods

Getters (accessors) return the value of a private field, and setters (mutators) change it, preserving encapsulation.
  • public int getAge() { return age; } is a standard accessor (getter).
  • public void setAge(int a) { age = a; } is a standard mutator (setter).
  • Encapsulation means keeping fields private and exposing controlled access via public methods.
  • Getters/setters let a class validate data (e.g. reject negative age) before changing state.
  • toString() is a special method that returns a String representation of an object, often overridden.

Method Signatures and Overloading

A method's signature is its name plus parameter types, and Java allows multiple methods with the same name if signatures differ.
  • public void bark(int times) and public void bark() are overloaded methods (different parameter lists).
  • Return type alone does NOT distinguish overloaded methods — parameter lists must differ.
  • Method parameters are passed by value: primitives are copied, and object references are copied (but point to the same object).
  • A void method returns nothing; a method with a return type must return a matching value on every path.
  • public static methods belong to the class itself, not an instance, and are called like ClassName.method().

Object References and Aliasing

A variable of an object type stores a reference (memory address) to the object, not the object itself, which leads to aliasing.
  • Dog a = new Dog("Rex", 3); Dog b = a; makes b an alias — both point to the same Dog object.
  • Changing b.setAge(5) also changes what a.getAge() returns, since they reference the same object.
  • null means a reference variable points to no object; calling a method on null throws a NullPointerException.
  • Two references are == only if they point to the exact same object in memory.
  • Passing an object to a method passes the reference, so the method can mutate the object's fields.

Inheritance Basics (Preview)

A class can extend another class to inherit its fields and methods, forming an 'is-a' relationship (fully explored in Unit 7).
  • class Puppy extends Dog { } makes Puppy inherit Dog's public and protected members.
  • super() calls the parent class's constructor and must be the first line in the subclass constructor.
  • protected members are accessible in the class, subclasses, and same package.
  • Overriding a method means redefining a parent method in the subclass with the same signature.
  • @Override is a common annotation (not required by AP exam) that flags an intentional override.
Writing a constructor with a return type (even void) — this makes it a regular method, not a constructor.
Forgetting this. when a parameter name matches a field name, causing the field to never actually update.
Assuming Dog b = a; copies the object — it only copies the reference; both variables alias the same object.
Comparing objects with == expecting value equality instead of reference equality.

Relational and Boolean Operators

Relational operators compare values and produce a boolean, while logical operators combine boolean expressions.
  • Relational operators: ==, !=, <, >, <=, >= compare numeric values and return true/false.
  • Logical AND (&&): both sides must be true for the whole expression to be true.
  • Logical OR (||): true if at least one side is true.
  • Logical NOT (!): flips a boolean's value, e.g. !true is false.
  • && and || use short-circuit evaluation: if the left side of && is false, the right side is never evaluated.

if, else if, else

Conditional statements let a program execute different code blocks depending on whether a boolean expression is true.
  • if (condition) { ... } else { ... } executes one branch or the other, never both.
  • else if chains test conditions in order; only the first true branch executes.
  • Conditions must be boolean expressions; Java does not allow if (1) like C does.
  • Nested if statements place one if inside another to test compound conditions.
  • Braces {} are optional for single-statement blocks but recommended to avoid dangling-else bugs.

De Morgan's Laws and Compound Conditions

De Morgan's Laws describe how to negate compound boolean expressions, a frequently tested exam skill.
  • !(A && B) is equivalent to (!A || !B).
  • !(A || B) is equivalent to (!A && !B).
  • Negating a relational operator flips it: !(x > 5) is equivalent to x <= 5.
  • Complex conditions can be simplified using truth tables to verify equivalence.
  • De Morgan's Laws are commonly tested by asking which expression is logically equivalent to a negated compound condition.

Comparing Objects vs Primitives

Comparing primitive values with == checks their actual value, but comparing objects with == checks reference identity, not content.
  • For primitives (int, double, boolean), == correctly compares values.
  • For objects (String, custom classes), == compares whether two references point to the same object.
  • String s1 = "cat"; String s2 = "cat"; s1 == s2 may be true due to String pooling, but this is unreliable — always use .equals().
  • new String("cat") == "cat" is false because new forces a distinct object.
  • compareTo() returns negative, zero, or positive to indicate ordering, e.g. "apple".compareTo("banana") is negative.

The Conditional (Ternary) Operator

The ternary operator ?: is a compact way to write a simple if-else that produces a value.
  • condition ? valueIfTrue : valueIfFalse; e.g. int max = (a > b) ? a : b;
  • The ternary operator's result can be assigned directly to a variable or printed.
  • Ternary expressions can be nested, but this quickly becomes hard to read.
  • Both branches must produce compatible types for the assignment to work.
  • Ternary operators are common in short evaluations but not required by the AP exam.

Truth Tables and Logical Equivalence

A truth table exhaustively lists every input combination and the resulting output, used to verify or compare boolean expressions.
  • For && there are 4 rows; only T,T yields true.
  • For || there are 4 rows; only F,F yields false.
  • Exclusive or (XOR) behavior can be built with (A || B) && !(A && B).
  • Two expressions are logically equivalent if their truth tables match on every row.
  • AP free-response questions sometimes ask you to trace boolean expressions with specific variable values.
Using = instead of == inside a condition, which assigns rather than compares (and often won't compile for non-boolean types).
Comparing Strings with ==, not .equals() — this trap resurfaces constantly across units.
Misapplying De Morgan's Law by forgetting to flip the relational operator along with the connective.
Assuming short-circuit && still evaluates the right side even when the left side is false — it does not.

while Loops

A while loop repeats a block of code as long as its boolean condition remains true, checked before each iteration.
  • while (condition) { ... } — the condition is checked before the loop body runs each time.
  • If the condition is false initially, the loop body never executes (0 iterations possible).
  • The loop variable must be updated inside the body, or the loop runs forever (infinite loop).
  • while (true) { ... break; } is a common pattern for loops with an exit condition inside the body.
  • while loops are ideal when the number of iterations isn't known in advance.

for Loops

A for loop packages initialization, condition, and update into one line, ideal for a known number of iterations.
  • for (int i = 0; i < n; i++) { ... } initializes i, checks i < n before each pass, then increments i after.
  • The loop runs n times for i = 0, 1, ..., n-1 (classic 0-indexed counting).
  • for (int i = n; i > 0; i--) counts downward from n to 1.
  • Any of the three for-loop clauses can be omitted, but the semicolons must remain.
  • Nested for loops (a loop inside a loop) are used for 2D array traversal and pattern printing.

do-while Loops

A do-while loop executes its body once before checking the condition, guaranteeing at least one execution.
  • do { ... } while (condition); checks the condition AFTER running the body.
  • Useful when code must run at least once regardless of the condition, e.g. menu prompts.
  • do-while loops are less common on the AP exam than while and for but still testable.
  • The semicolon after while (condition) in a do-while is required (a common syntax slip).
  • Off-by-one behavior differs from while: a do-while with a false condition still runs once.

Loop Control: break and continue

break exits a loop entirely, while continue skips to the next iteration without finishing the current one.
  • break immediately terminates the nearest enclosing loop (or switch).
  • continue skips the rest of the current iteration's body and jumps to the loop's update/condition check.
  • In a for loop, continue still executes the increment (i++) before re-checking the condition.
  • Overusing break/continue can make loop logic harder to trace; AP favors clear conditions when possible.
  • break only exits the innermost loop it's directly inside, not outer loops in nested structures.

Off-By-One Errors and Loop Bounds

Off-by-one errors occur when a loop iterates one time too many or too few, often due to boundary condition mistakes.
  • for (int i = 0; i <= n; i++) runs n+1 times, which often causes an IndexOutOfBoundsException on arrays of size n.
  • The safe array-traversal bound is i < arr.length, not i <= arr.length.
  • Changing < to <= (or vice versa) in a loop condition is a classic single-character bug.
  • Tracing a loop by hand with a small example (n=3) quickly reveals off-by-one mistakes.
  • Reversed iteration for (int i = arr.length - 1; i >= 0; i--) correctly visits every valid index.

Accumulator Patterns

An accumulator pattern uses a loop to build up a running result, such as a sum, count, product, or maximum.
  • int sum = 0; for (int x : arr) { sum += x; } accumulates a running total.
  • int count = 0; for (...) { if (condition) count++; } counts matching elements.
  • double product = 1; ... product *= x; is the multiplicative accumulator pattern (starts at 1, not 0).
  • Finding a maximum: initialize max to the first element (or a very small value), then compare and update.
  • Accumulator variables must be declared and initialized BEFORE the loop begins, not inside it.
Using <= instead of < in an array loop bound, causing ArrayIndexOutOfBoundsException.
Forgetting to update the loop control variable, creating an infinite loop.
Initializing an accumulator inside the loop instead of before it, resetting it every iteration.
Assuming do-while behaves like while — do-while always executes its body at least once.

Declaring and Creating Arrays

An array is a fixed-size, ordered collection of elements of the same type, indexed starting at 0.
  • int[] nums = new int[5]; creates an array of 5 ints, all initialized to 0.
  • int[] nums = {1, 2, 3}; creates and initializes an array literal in one step.
  • Array length is fixed at creation; nums.length gives the size (no parentheses — it's a field, not a method).
  • Valid indices range from 0 to length - 1; accessing arr[arr.length] throws ArrayIndexOutOfBoundsException.
  • Array elements default to 0 for numeric types, false for boolean, and null for object types.

Traversing Arrays

Arrays are commonly traversed with a standard for loop (for index access) or an enhanced for-each loop (for read-only access).
  • for (int i = 0; i < arr.length; i++) gives index-based access, needed when modifying elements.
  • for (int x : arr) { ... } is the enhanced for-each loop; x is a copy, so you cannot modify arr through it.
  • Reversing an array in place swaps arr[i] and arr[arr.length-1-i] for i from 0 to length/2.
  • Searching linearly checks each element in order until a match is found or the array ends.
  • The for-each loop cannot access the index, only the value, so use a regular for loop when the index matters.

Common Array Algorithms

Several standard algorithms — linear search, finding min/max, and sum/average — appear frequently on the AP exam.
  • Linear search: loop through checking arr[i] == target; return index if found, -1 if the loop finishes without a match.
  • Finding the max: initialize max = arr[0], then compare each subsequent element and update if larger.
  • Sum and average: accumulate a sum with a loop, then divide by arr.length (cast to double to avoid integer division).
  • Counting occurrences: loop and increment a counter whenever arr[i] matches a condition.
  • Checking if an array is sorted: compare each adjacent pair arr[i] <= arr[i+1] across the whole array.

Arrays as Method Parameters

Arrays are objects in Java, so passing an array to a method passes a reference, allowing the method to modify the caller's array.
  • public static void doubleAll(int[] arr) { for (int i=0; i<arr.length; i++) arr[i] *= 2; } permanently changes the caller's array.
  • Methods can return arrays: public static int[] makeArray(int n) { ... return result; }
  • Arrays.toString(arr) converts an array to a printable String like [1, 2, 3].
  • You cannot resize an array; to 'grow' it, you must create a new, larger array and copy elements over.
  • System.arraycopy() or a manual loop is used to copy elements between arrays.

Selection Sort and Insertion Sort

AP CSA requires knowing two $O(n^2)$ sorting algorithms by name and behavior: selection sort and insertion sort.
  • Selection sort repeatedly finds the minimum of the unsorted portion and swaps it into place at the front.
  • Selection sort makes exactly n-1 swaps regardless of initial order.
  • Insertion sort builds a sorted portion at the front by taking each next element and shifting it into place.
  • Insertion sort performs well on nearly-sorted data (fewer shifts needed) while selection sort's work is constant.
  • Both selection sort and insertion sort run in $O(n^2)$ time in the worst case.

Binary Search

Binary search efficiently finds a target in a SORTED array by repeatedly halving the search range, running in O(log n) time.
  • Binary search requires the array to already be sorted; it fails on unsorted data.
  • Compare the target to the middle element: if equal, found; if target is smaller, search the left half; if larger, search the right half.
  • int mid = (low + high) / 2; is the standard midpoint calculation.
  • Binary search runs in O(log n) time, dramatically faster than linear search's O(n) on large arrays.
  • The loop/recursion ends when low > high (not found, return -1) or the target is located.
Using arr.length() with parentheses — for arrays it's arr.length, a field, not a method call.
Off-by-one with < vs <= in array loop bounds, causing ArrayIndexOutOfBoundsException.
Running binary search on an unsorted array — it silently gives wrong results instead of erroring.
Assuming a for-each loop (for (int x : arr)) can modify the original array — it only has a copy of each value.

ArrayList Basics

ArrayList is a resizable, generic collection class in java.util that grows and shrinks dynamically, unlike fixed-size arrays.
  • ArrayList<String> list = new ArrayList<String>(); declares and creates an empty ArrayList of Strings.
  • list.add("cat") appends to the end; list.add(0, "dog") inserts at a specific index.
  • list.get(i) retrieves the element at index i; list.set(i, val) replaces it.
  • list.size() returns the number of elements currently stored (like arr.length, but it's a method with parentheses).
  • ArrayLists only hold objects (reference types), so primitives like int are autoboxed to Integer.

Modifying an ArrayList

ArrayLists support insertion and removal anywhere, automatically shifting elements to keep indices contiguous.
  • list.remove(i) removes by index (int argument); list.remove(Object o) removes by value.
  • list.remove(2) removes the element AT index 2; list.remove(Integer.valueOf(2)) removes the value 2.
  • Removing or adding elements shifts all subsequent elements' indices, which can break a forward-iterating loop.
  • list.contains(val) returns true/false; list.indexOf(val) returns the index or -1 if absent.
  • list.clear() removes all elements, resetting size() to 0.

Traversing and Removing Safely

Because removal shifts indices, looping forward while removing elements is a classic AP CSA bug; looping backward avoids it.
  • for (int i = 0; i < list.size(); i++) { if (cond) list.remove(i); } can skip elements after a removal.
  • The fix: iterate backward — for (int i = list.size()-1; i >= 0; i--) — so shifting doesn't skip unvisited elements.
  • Using a for-each loop while modifying the list throws a ConcurrentModificationException.
  • An alternative fix is to build a new ArrayList of items to keep instead of removing in place.
  • size() must be re-checked each loop iteration since it changes as elements are added/removed.

ArrayList vs Array

ArrayLists trade some performance and syntax simplicity for dynamic resizing and built-in convenience methods that arrays lack.
  • Arrays have fixed size set at creation; ArrayLists grow and shrink automatically via add/remove.
  • Arrays use [] syntax (arr[i]); ArrayLists use method calls (list.get(i), list.set(i, val)).
  • Arrays can hold primitives directly; ArrayLists require wrapper classes (ArrayList<Integer>, not ArrayList<int>).
  • Arrays use .length (field); ArrayLists use .size() (method with parentheses).
  • Converting: many algorithms are easier to write on arrays first, then adapted for ArrayLists.

Reference Semantics with ArrayLists

Like all objects, ArrayLists are manipulated by reference, so aliasing and pass-by-reference rules from Unit 2 apply here too.
  • ArrayList<String> b = a; makes b an alias of a — modifying b also changes what a sees.
  • Passing an ArrayList to a method allows that method to permanently modify its contents (add/remove/set).
  • To make an independent copy, use new ArrayList<>(originalList), which copies references to elements, not a deep copy.
  • Comparing two ArrayLists with == checks reference identity; use .equals() to check if their contents match.
  • Wrapper class objects like Integer should be compared with .equals() or unboxed for value comparison, not ==, for values outside the small cached range.

Common ArrayList Algorithms

Many array algorithms — search, sum, filter — translate directly to ArrayLists using get() and size() instead of [] and length.
  • Linear search: for (int i = 0; i < list.size(); i++) if (list.get(i).equals(target)) return i;
  • Sum: for (int x : list) sum += x; works because ArrayList<Integer> auto-unboxes in arithmetic.
  • Filtering into a new list: create ArrayList<T> result, loop through source, add matching elements.
  • Finding max: track a running max object, compare using .compareTo() for Comparable types like Integer or String.
  • Removing all elements matching a condition safely requires backward iteration or list.removeIf() (not always covered but useful).
Calling list.length instead of list.size() — ArrayLists never use .length.
Removing elements in a forward for loop, which skips the element that shifts into the just-vacated index.
Writing list.remove(2) when meaning to remove the value 2 from an ArrayList<Integer> — it removes the element AT index 2 instead.
Assuming a for-each loop can be used to remove elements — it throws ConcurrentModificationException.

Declaring and Traversing 2D Arrays

A 2D array is an array of arrays, commonly visualized as a grid with rows and columns, indexed as arr[row][col].
  • int[][] grid = new int[3][4]; creates a grid with 3 rows and 4 columns, all initialized to 0.
  • int[][] grid = {{1,2},{3,4},{5,6}}; creates and initializes a 2D array literal with 3 rows of 2 columns each.
  • grid.length gives the number of rows; grid[0].length gives the number of columns in row 0.
  • Nested for loops traverse a 2D array: outer loop for rows, inner loop for columns — for (int r=0;r<grid.length;r++) for (int c=0;c<grid[r].length;c++).
  • Rows in a 2D array can have different lengths (a 'ragged' or jagged array) since each row is itself a separate array.

Row-Major vs Column-Major Traversal

The order in which nested loops iterate rows and columns changes the order elements are visited, though not which elements exist.
  • Row-major traversal: outer loop over rows, inner loop over columns — visits grid[0][0], grid[0][1], ... row by row.
  • Column-major traversal: outer loop over columns, inner loop over rows — visits grid[0][0], grid[1][0], ... column by column.
  • Summing an entire 2D array requires visiting every [r][c] pair exactly once, in either traversal order.
  • Diagonal traversal (grid[i][i]) only works cleanly on square (n x n) grids.
  • AP free-response often asks to trace or write nested-loop code that processes only part of a grid (e.g. one row).

Inheritance: extends and super

A subclass inherits fields and methods from a superclass using extends, modeling an 'is-a' relationship between classes.
  • class Cat extends Animal { } makes Cat a subclass of Animal, inheriting its public/protected members.
  • super(args) calls the superclass constructor and must be the very first statement in the subclass constructor.
  • super.methodName() explicitly calls the superclass's version of a method (useful when overriding).
  • A subclass does NOT inherit private fields/methods directly, but can access them through inherited public/protected methods.
  • Every class in Java implicitly extends Object if no other superclass is specified.

Overriding Methods and Polymorphism

Overriding lets a subclass provide its own implementation of a method inherited from its superclass, enabling polymorphic behavior.
  • An overriding method must have the same name, parameter list, and a compatible return type as the parent's method.
  • Animal a = new Cat(); a.makeSound(); calls Cat's overridden makeSound(), not Animal's — this is dynamic (runtime) binding.
  • Polymorphism means a superclass reference variable can hold subclass objects, and the actual object's type determines which overridden method runs.
  • Overloading (same name, different parameters) is resolved at compile time; overriding (same signature) is resolved at runtime.
  • instanceof checks an object's actual runtime type, e.g. if (a instanceof Cat) allows safe downcasting.

Abstract Classes and Interfaces

Abstract classes and interfaces define contracts that other classes must fulfill, supporting polymorphism without full implementation.
  • An abstract class (abstract class Shape { abstract double area(); }) cannot be instantiated directly with new.
  • A subclass of an abstract class must override all abstract methods or itself be declared abstract.
  • An interface (interface Comparable) specifies method signatures that implementing classes must define, using implements.
  • A class can implement multiple interfaces but can only extend one superclass (Java has single inheritance for classes).
  • Comparable<T> requires a compareTo(T other) method, used by Collections.sort() and similar utilities.

The Object Superclass and equals()

Every Java class inherits from Object, which provides default equals(), toString(), and hashCode() methods that are often overridden.
  • The default Object.equals() checks reference equality (same as ==) unless a class overrides it.
  • Overriding equals(Object other) lets a class define logical (content-based) equality, e.g. two Points with the same x,y.
  • toString() is called implicitly by System.out.println(obj) and string concatenation with an object.
  • A well-written equals() typically checks the parameter's type/cast before comparing fields.
  • Overriding equals() without overriding hashCode() can cause inconsistent behavior in hash-based collections (a conceptual note, not tested in depth on AP CSA).
Swapping row and column indices (grid[col][row] instead of grid[row][col]), scrambling the grid's meaning.
Forgetting super(args) must be the first statement, causing a compile error if other code precedes it.
Confusing overriding with overloading — overriding needs the exact same parameters; overloading needs different ones.
Assuming grid[r].length is the same for every row — jagged 2D arrays can have different-length rows.

Recursion Fundamentals

A recursive method calls itself to solve smaller instances of the same problem, requiring a base case to stop the recursion.
  • Every recursive method needs a base case (a condition that returns without recursing) to avoid infinite recursion.
  • The recursive case calls the method again on a smaller/simpler version of the problem, moving toward the base case.
  • public static int factorial(int n) { if (n == 0) return 1; return n * factorial(n-1); } is a classic example.
  • Each recursive call gets its own stack frame with its own copies of local variables and parameters.
  • Missing or unreachable base cases cause a StackOverflowError at runtime.

Tracing Recursive Calls

Tracing recursion means following each call down to the base case, then following the returns back up, often drawn as a call stack or tree.
  • factorial(4) calls factorial(3), which calls factorial(2), ..., down to factorial(0), which returns 1 directly.
  • Return values propagate back up: factorial(1)=1*1=1, factorial(2)=2*1=2, factorial(3)=3*2=6, factorial(4)=4*6=24.
  • Drawing an explicit call stack (each call waiting for the one below it to return) helps avoid trace errors.
  • Recursive Fibonacci fib(n) = fib(n-1) + fib(n-2) makes TWO recursive calls per non-base case, forming a call tree.
  • AP free-response frequently asks students to trace a recursive method's output for a specific input by hand.

Recursion on Strings and Arrays

Recursion can process Strings and arrays by operating on one element and recursing on the rest (a smaller substring or sub-array).
  • Recursive string reversal: reverse(s) = reverse(s.substring(1)) + s.charAt(0), with base case s.length() <= 1.
  • Recursive array sum: sum(arr, i) = arr[i] + sum(arr, i+1), with base case i == arr.length returning 0.
  • Recursive linear search on an array checks index i, then recurses on i+1 if no match, base case i == arr.length.
  • Palindrome check recursively compares the first and last characters, then recurses on the substring between them.
  • Recursion on a String typically shrinks via substring(); recursion on an array typically shrinks via an index parameter.

Recursion vs Iteration

Any recursive algorithm can be rewritten iteratively with a loop, and choosing between them is a matter of clarity versus overhead.
  • Recursive solutions are often more concise for problems with a naturally recursive structure (trees, divide-and-conquer).
  • Iterative solutions avoid the memory overhead of building up many stack frames.
  • Deep recursion (very large n) risks StackOverflowError, while an equivalent loop does not.
  • Recursion is required conceptually for algorithms like merge sort, even though loops handle simpler tasks like summing an array.
  • AP CSA expects you to convert between simple recursive and iterative versions of the same algorithm.

Recursive Binary Search

Binary search can be implemented recursively, recursing into the left or right half of a sorted array based on a midpoint comparison.
  • binarySearch(arr, target, low, high): base case is low > high, returning -1 (not found).
  • If arr[mid] == target, return mid; if target < arr[mid], recurse on (low, mid-1); else recurse on (mid+1, high).
  • Each recursive call halves the search space, giving binary search its O(log n) time complexity.
  • Recursive binary search requires the array to be sorted, same as the iterative version.
  • int mid = low + (high - low) / 2; avoids potential overflow compared to (low + high) / 2 (a subtle but real detail).

Merge Sort and Big-O Basics

Merge sort is a recursive, divide-and-conquer sorting algorithm running in O(n log n) time, and Big-O describes algorithm efficiency as input grows.
  • Merge sort recursively splits the array in half, sorts each half, then merges the two sorted halves back together.
  • Merge sort runs in O(n log n) time, faster than selection/insertion sort's $O(n^2)$ for large inputs.
  • Big-O notation describes worst-case growth rate: O(1) constant, O(log n) logarithmic, O(n) linear, $O(n^2)$ quadratic.
  • Linear search is O(n); binary search is O(log n); selection/insertion sort are $O(n^2)$; merge sort is O(n log n).
  • The merge step combines two already-sorted halves by repeatedly comparing their front elements and taking the smaller.
Forgetting the base case entirely, or writing one that's never actually reached, causing infinite recursion.
Tracing recursive calls in the wrong order — remember calls return in reverse (last call in, first to return).
Assuming recursion is always faster than iteration — it often has more overhead due to stack frames.
Mixing up which recursive call handles the 'left half' vs 'right half' in recursive binary search, breaking the search.
Term
Press Enter or Space to flip the card. Left and right arrows move between cards. 1 marks it known, 2 marks it still learning.
Click or press Enter to flip · Rate yourself to track weak cards
Browse all 80 flashcards as a list

Unit 1: Java Basics & Primitive Types

int
A primitive type storing a 32-bit signed whole number, e.g. int x = 5;
double
A primitive type storing a double-precision decimal number, e.g. double pi = 3.14;
Integer division
Division between two ints truncates the decimal part: 7 / 2 evaluates to 3.
Casting
Explicitly converting one type to another, e.g. (int) 4.9 truncates to 4.
String concatenation
Joining strings (or a string and another type) with the + operator, e.g. "a" + 1 gives "a1".
.equals()
The correct method for comparing the content of two String or object references for equality.
== (primitives vs objects)
For primitives, == compares values; for objects, == compares whether two references point to the same object.
Math.random()
A static method returning a random double in the range [0.0, 1.0).
Modulus (%)
Returns the remainder of integer division, e.g. 7 % 2 is 1.
javac / java
javac compiles .java source into .class bytecode; java runs that bytecode on the JVM.

Unit 2: Objects & Classes

Class
A blueprint defining the instance variables and methods that its objects will have.
Object
A specific instance of a class, created with the new keyword.
Constructor
A special method matching the class name, with no return type, used to initialize a new object.
this
A keyword referring to the current object, often used to resolve naming conflicts with parameters.
Accessor (getter)
A public method that returns the value of a private instance variable, e.g. getAge().
Mutator (setter)
A public method that changes the value of a private instance variable, e.g. setAge(int a).
Encapsulation
Keeping fields private and controlling access to them through public methods.
Method overloading
Defining multiple methods with the same name but different parameter lists in one class.
Aliasing
When two reference variables point to the same object, so changes through one are visible through the other.
NullPointerException
A runtime error thrown when calling a method or accessing a field on a reference that is null.

Unit 3: Boolean Logic & Ifs

&& (logical AND)
True only when both operands are true; short-circuits if the left operand is false.
|| (logical OR)
True if at least one operand is true; short-circuits if the left operand is true.
Short-circuit evaluation
The right operand of && or || is skipped when the left operand already determines the result.
De Morgan's Laws
!(A && B) equals (!A || !B), and !(A || B) equals (!A && !B).
Ternary operator
A compact conditional expression: condition ? valueIfTrue : valueIfFalse.
compareTo()
A method returning negative, zero, or positive to indicate the relative order of two Comparable values.
if / else if / else
A conditional chain where only the first branch with a true condition executes.
Dangling else
An ambiguity risk when braces are omitted, causing an else to bind to an unintended if.
Boolean expression
Any expression that evaluates to true or false; required inside if, while, and for's condition clause.
Truth table
A table listing every combination of boolean inputs and the resulting output of an expression.

Unit 4: Iteration Loops

while loop
A loop that checks its condition before each iteration; may run zero times.
do-while loop
A loop that checks its condition after each iteration, guaranteeing at least one execution.
for loop
A loop combining initialization, condition, and update in one header, ideal for a known iteration count.
break
A statement that immediately exits the nearest enclosing loop or switch statement.
continue
A statement that skips the rest of the current iteration and proceeds to the loop's next check/update.
Off-by-one error
A bug where a loop runs one time too many or too few, often from using <= instead of <.
Accumulator pattern
A loop pattern that builds up a result (sum, count, product) across iterations using a variable initialized before the loop.
Infinite loop
A loop whose condition never becomes false, typically because the control variable is never updated.
Nested loop
A loop placed inside the body of another loop, commonly used for 2D traversal.
Loop invariant
A condition that remains true before and after each iteration of a loop, useful for reasoning about correctness.

Unit 5: Arrays

Array
A fixed-size, ordered collection of elements of the same type, indexed from 0.
arr.length
A field (not a method) giving the number of elements in an array.
ArrayIndexOutOfBoundsException
A runtime error thrown when accessing an index outside 0 to arr.length - 1.
Enhanced for loop (for-each)
A loop that iterates over each element's value without exposing its index, e.g. for (int x : arr).
Linear search
An algorithm checking each element in order until a match is found or the array ends; O(n) time.
Binary search
An algorithm that repeatedly halves a sorted array's search range to find a target in O(log n) time.
Selection sort
A sorting algorithm that repeatedly finds the minimum of the unsorted portion and swaps it into place.
Insertion sort
A sorting algorithm that builds a sorted portion by shifting each new element into its correct position.
Arrays.toString()
A utility method that converts an array into a readable String like [1, 2, 3].
Pass-by-reference (arrays)
Passing an array to a method passes its reference, so the method can permanently modify the original array's contents.

Unit 6: ArrayLists & References

ArrayList
A resizable, generic collection class from java.util that grows and shrinks dynamically.
list.size()
A method (with parentheses) returning the current number of elements in an ArrayList.
list.add(index, val)
Inserts val at the given index, shifting subsequent elements to the right.
list.remove(int)
Removes the element AT the given index (not the element equal to that value).
ConcurrentModificationException
An error thrown when modifying an ArrayList (add/remove) while iterating over it with a for-each loop.
Backward iteration
Looping from the last index to 0 when removing elements, to avoid skipping elements as indices shift.
Autoboxing
Java's automatic conversion between a primitive (like int) and its wrapper class (like Integer) as needed.
ArrayList<Integer>
An ArrayList that stores Integer objects, since generic collections cannot hold primitive types directly.
list.contains()
Returns true if the ArrayList holds an element equal to the given value, false otherwise.
Reference aliasing (ArrayList)
Assigning one ArrayList variable to another copies the reference, so both variables point to the same list.

Unit 7: 2D Arrays & Inheritance

2D array
An array of arrays, accessed as arr[row][col], commonly visualized as a grid.
Jagged array
A 2D array whose rows can have different lengths, since each row is a separate array object.
extends
The keyword a subclass uses to inherit fields and methods from a superclass.
super()
A call to the superclass's constructor; must be the first statement in a subclass constructor.
Method overriding
Redefining an inherited method in a subclass using the exact same method signature.
Polymorphism
A superclass reference can hold a subclass object, and overridden methods run based on the object's actual runtime type.
instanceof
An operator that checks whether an object is an instance of a given class at runtime.
Abstract class
A class that cannot be instantiated directly and may declare abstract methods that subclasses must implement.
Interface
A contract of method signatures that an implementing class must define, using the implements keyword.
Dynamic (runtime) binding
The mechanism by which Java decides which overridden method to call based on the object's actual type, not the reference's declared type.

Unit 8: Recursion & Algorithms

Recursion
A technique where a method calls itself to solve smaller instances of the same problem.
Base case
The condition in a recursive method that stops further recursive calls and returns directly.
Recursive case
The part of a recursive method that calls itself again on a smaller version of the problem.
StackOverflowError
A runtime error caused by recursion that never reaches its base case, exhausting the call stack.
Call stack
The stack of active method calls, each waiting for the call below it to return before it can finish.
Recursive binary search
A version of binary search that recurses into the left or right half of a sorted array instead of looping.
Merge sort
A recursive divide-and-conquer sorting algorithm that splits, sorts, and merges halves in O(n log n) time.
Big-O notation
A way of describing an algorithm's worst-case growth rate as input size increases, e.g. O(n), O(log n), $O(n^2)$.
O(log n)
Logarithmic time complexity, characteristic of algorithms like binary search that repeatedly halve the problem size.
$O(n^2)$
Quadratic time complexity, characteristic of algorithms like selection sort and insertion sort.
Press 1–4 to answer · Enter for next

Unit 1: Java Basics & Primitive Types

Compiling and Running Java
Java source code (.java) is compiled by javac into bytecode (.class), which the JVM executes, making Java platform-independent.
Primitive Types: int and double
AP CSA uses int for whole numbers and double for decimal (floating-point) numbers as the two primary numeric types.
Variables, Declarations, and Assignment
A variable must be declared with a type before use, and assignment stores a value into that variable's memory location.
String Basics
String objects represent immutable sequences of characters and support several key methods tested on the AP exam.
Expressions and Operator Precedence
Java evaluates expressions following a strict order of operations, similar to standard math precedence rules.
Wrapper Classes and Integer Overflow
Java provides wrapper classes like Integer and Double to treat primitives as objects, and ints have a fixed range that can overflow.
Key fact
int / int always truncates toward zero; cast one operand to double to get a decimal result.
Key fact
String comparison must use .equals(), never == (== compares object references, not content).
Key fact
Java is case-sensitive: int, String, and boolean must be lowercase/exact-case keywords.
Key fact
Every statement ends in a semicolon; blocks of code are grouped with { }.

Unit 2: Objects & Classes

Classes as Blueprints
A class defines the instance variables (state) and methods (behavior) that every object created from it will have.
Constructors
A constructor initializes a new object's instance variables and shares its name with the class.
Accessor and Mutator Methods
Getters (accessors) return the value of a private field, and setters (mutators) change it, preserving encapsulation.
Method Signatures and Overloading
A method's signature is its name plus parameter types, and Java allows multiple methods with the same name if signatures differ.
Object References and Aliasing
A variable of an object type stores a reference (memory address) to the object, not the object itself, which leads to aliasing.
Inheritance Basics (Preview)
A class can extend another class to inherit its fields and methods, forming an 'is-a' relationship (fully explored in Unit 7).
Key fact
Constructors share the class name and have no return type, including no void.
Key fact
this.field = parameter is the standard fix when a constructor parameter shadows a field name.
Key fact
Objects are compared for identity with ==, but for logical equality you should use .equals().
Key fact
Private fields are only directly accessible inside their own class's methods.

Unit 3: Boolean Logic & Ifs

Relational and Boolean Operators
Relational operators compare values and produce a boolean, while logical operators combine boolean expressions.
if, else if, else
Conditional statements let a program execute different code blocks depending on whether a boolean expression is true.
De Morgan's Laws and Compound Conditions
De Morgan's Laws describe how to negate compound boolean expressions, a frequently tested exam skill.
Comparing Objects vs Primitives
Comparing primitive values with == checks their actual value, but comparing objects with == checks reference identity, not content.
The Conditional (Ternary) Operator
The ternary operator ?: is a compact way to write a simple if-else that produces a value.
Truth Tables and Logical Equivalence
A truth table exhaustively lists every input combination and the resulting output, used to verify or compare boolean expressions.
Key fact
&& and || short-circuit: the right operand may never execute if the left already determines the result.
Key fact
Always use .equals() for String/object content comparison; == is for primitives and reference identity.
Key fact
De Morgan's Laws: !(A&&B) == (!A||!B) and !(A||B) == (!A&&!B).
Key fact
A boolean-valued condition is required inside if(), while(), and the middle clause of for().

Unit 4: Iteration Loops

while Loops
A while loop repeats a block of code as long as its boolean condition remains true, checked before each iteration.
for Loops
A for loop packages initialization, condition, and update into one line, ideal for a known number of iterations.
do-while Loops
A do-while loop executes its body once before checking the condition, guaranteeing at least one execution.
Loop Control: break and continue
break exits a loop entirely, while continue skips to the next iteration without finishing the current one.
Off-By-One Errors and Loop Bounds
Off-by-one errors occur when a loop iterates one time too many or too few, often due to boundary condition mistakes.
Accumulator Patterns
An accumulator pattern uses a loop to build up a running result, such as a sum, count, product, or maximum.
Key fact
while checks its condition before running; do-while checks after, guaranteeing at least one execution.
Key fact
for (int i = 0; i < arr.length; i++) is the standard safe way to traverse an array by index.
Key fact
break exits the loop entirely; continue skips only to the next iteration.
Key fact
A sum accumulator starts at 0; a product accumulator starts at 1.

Unit 5: Arrays

Declaring and Creating Arrays
An array is a fixed-size, ordered collection of elements of the same type, indexed starting at 0.
Traversing Arrays
Arrays are commonly traversed with a standard for loop (for index access) or an enhanced for-each loop (for read-only access).
Common Array Algorithms
Several standard algorithms — linear search, finding min/max, and sum/average — appear frequently on the AP exam.
Arrays as Method Parameters
Arrays are objects in Java, so passing an array to a method passes a reference, allowing the method to modify the caller's array.
Selection Sort and Insertion Sort
AP CSA requires knowing two $O(n^2)$ sorting algorithms by name and behavior: selection sort and insertion sort.
Binary Search
Binary search efficiently finds a target in a SORTED array by repeatedly halving the search range, running in O(log n) time.
Key fact
Array indices run from 0 to arr.length - 1; arr.length has no parentheses (it's a field).
Key fact
Arrays are reference types: passing one to a method lets that method modify the original array's contents.
Key fact
Binary search requires a sorted array and runs in O(log n); linear search works unsorted in O(n).
Key fact
Selection sort always makes n-1 swaps; insertion sort's work depends on how sorted the data already is.

Unit 6: ArrayLists & References

ArrayList Basics
ArrayList is a resizable, generic collection class in java.util that grows and shrinks dynamically, unlike fixed-size arrays.
Modifying an ArrayList
ArrayLists support insertion and removal anywhere, automatically shifting elements to keep indices contiguous.
Traversing and Removing Safely
Because removal shifts indices, looping forward while removing elements is a classic AP CSA bug; looping backward avoids it.
ArrayList vs Array
ArrayLists trade some performance and syntax simplicity for dynamic resizing and built-in convenience methods that arrays lack.
Reference Semantics with ArrayLists
Like all objects, ArrayLists are manipulated by reference, so aliasing and pass-by-reference rules from Unit 2 apply here too.
Common ArrayList Algorithms
Many array algorithms — search, sum, filter — translate directly to ArrayLists using get() and size() instead of [] and length.
Key fact
ArrayList uses .size() (a method) while arrays use .length (a field) — mixing these up is a compile error.
Key fact
ArrayList<Integer> can only hold Integer objects, not primitive int, due to Java generics restrictions.
Key fact
list.remove(int) removes by index; list.remove(Object) removes by matching value — overload ambiguity with Integer is a classic trap.
Key fact
Removing elements while iterating forward with indices can skip elements; iterate backward to remove safely.

Unit 7: 2D Arrays & Inheritance

Declaring and Traversing 2D Arrays
A 2D array is an array of arrays, commonly visualized as a grid with rows and columns, indexed as arr[row][col].
Row-Major vs Column-Major Traversal
The order in which nested loops iterate rows and columns changes the order elements are visited, though not which elements exist.
Inheritance: extends and super
A subclass inherits fields and methods from a superclass using extends, modeling an 'is-a' relationship between classes.
Overriding Methods and Polymorphism
Overriding lets a subclass provide its own implementation of a method inherited from its superclass, enabling polymorphic behavior.
Abstract Classes and Interfaces
Abstract classes and interfaces define contracts that other classes must fulfill, supporting polymorphism without full implementation.
The Object Superclass and equals()
Every Java class inherits from Object, which provides default equals(), toString(), and hashCode() methods that are often overridden.
Key fact
2D array access is grid[row][col]; grid.length is the row count, grid[0].length is the column count of row 0.
Key fact
super(...) must be the first line of a subclass constructor if used at all.
Key fact
Overriding requires an identical method signature; overloading requires a different parameter list.
Key fact
A superclass reference can point to a subclass object, and overridden methods run based on the object's actual type (dynamic binding).

Unit 8: Recursion & Algorithms

Recursion Fundamentals
A recursive method calls itself to solve smaller instances of the same problem, requiring a base case to stop the recursion.
Tracing Recursive Calls
Tracing recursion means following each call down to the base case, then following the returns back up, often drawn as a call stack or tree.
Recursion on Strings and Arrays
Recursion can process Strings and arrays by operating on one element and recursing on the rest (a smaller substring or sub-array).
Recursion vs Iteration
Any recursive algorithm can be rewritten iteratively with a loop, and choosing between them is a matter of clarity versus overhead.
Recursive Binary Search
Binary search can be implemented recursively, recursing into the left or right half of a sorted array based on a midpoint comparison.
Merge Sort and Big-O Basics
Merge sort is a recursive, divide-and-conquer sorting algorithm running in O(n log n) time, and Big-O describes algorithm efficiency as input grows.
Key fact
Every correct recursive method needs a base case and a recursive case that moves toward it.
Key fact
Recursive calls build a call stack; unreachable base cases cause a StackOverflowError.
Key fact
Binary search and merge sort both run in O(log n) and O(n log n) respectively, beating linear-time and $O(n^2)$ alternatives.
Key fact
Big-O order from fastest to slowest growth: O(1) < O(log n) < O(n) < O(n log n) < $O(n^2)$.
Common mistakes for each unit — read the mistake, then make sure you know why it's wrong.

Unit 1: Java Basics & Primitive Types

Watch out
Using == to compare Strings, not .equals() — == checks if two references point to the same object.
Watch out
Expecting 5 / 2 to equal 2.5, not 2 — integer division truncates the decimal part entirely.
Watch out
Forgetting that (int) casting truncates toward zero, not rounds — (int) 4.9 is 4, not 5.
Watch out
Confusing = (assignment) with == (equality comparison) inside conditions.

Unit 2: Objects & Classes

Watch out
Writing a constructor with a return type (even void) — this makes it a regular method, not a constructor.
Watch out
Forgetting this. when a parameter name matches a field name, causing the field to never actually update.
Watch out
Assuming Dog b = a; copies the object — it only copies the reference; both variables alias the same object.
Watch out
Comparing objects with == expecting value equality instead of reference equality.

Unit 3: Boolean Logic & Ifs

Watch out
Using = instead of == inside a condition, which assigns rather than compares (and often won't compile for non-boolean types).
Watch out
Comparing Strings with ==, not .equals() — this trap resurfaces constantly across units.
Watch out
Misapplying De Morgan's Law by forgetting to flip the relational operator along with the connective.
Watch out
Assuming short-circuit && still evaluates the right side even when the left side is false — it does not.

Unit 4: Iteration Loops

Watch out
Using <= instead of < in an array loop bound, causing ArrayIndexOutOfBoundsException.
Watch out
Forgetting to update the loop control variable, creating an infinite loop.
Watch out
Initializing an accumulator inside the loop instead of before it, resetting it every iteration.
Watch out
Assuming do-while behaves like while — do-while always executes its body at least once.

Unit 5: Arrays

Watch out
Using arr.length() with parentheses — for arrays it's arr.length, a field, not a method call.
Watch out
Off-by-one with < vs <= in array loop bounds, causing ArrayIndexOutOfBoundsException.
Watch out
Running binary search on an unsorted array — it silently gives wrong results instead of erroring.
Watch out
Assuming a for-each loop (for (int x : arr)) can modify the original array — it only has a copy of each value.

Unit 6: ArrayLists & References

Watch out
Calling list.length instead of list.size() — ArrayLists never use .length.
Watch out
Removing elements in a forward for loop, which skips the element that shifts into the just-vacated index.
Watch out
Writing list.remove(2) when meaning to remove the value 2 from an ArrayList<Integer> — it removes the element AT index 2 instead.
Watch out
Assuming a for-each loop can be used to remove elements — it throws ConcurrentModificationException.

Unit 7: 2D Arrays & Inheritance

Watch out
Swapping row and column indices (grid[col][row] instead of grid[row][col]), scrambling the grid's meaning.
Watch out
Forgetting super(args) must be the first statement, causing a compile error if other code precedes it.
Watch out
Confusing overriding with overloading — overriding needs the exact same parameters; overloading needs different ones.
Watch out
Assuming grid[r].length is the same for every row — jagged 2D arrays can have different-length rows.

Unit 8: Recursion & Algorithms

Watch out
Forgetting the base case entirely, or writing one that's never actually reached, causing infinite recursion.
Watch out
Tracing recursive calls in the wrong order — remember calls return in reverse (last call in, first to return).
Watch out
Assuming recursion is always faster than iteration — it often has more overhead due to stack frames.
Watch out
Mixing up which recursive call handles the 'left half' vs 'right half' in recursive binary search, breaking the search.