AP CSA Unit 2 Notes: Decision-Making with Booleans and Conditionals
Algorithms with Selection and Repetition
An algorithm is a step-by-step process for solving a problem. In programming, you rarely write a straight-line algorithm that runs the same steps every time—real programs need to choose between actions and repeat actions until some goal is met. That’s where selection and repetition come in.
Selection means your algorithm makes a decision and follows one path or another. In Java, selection is primarily implemented with if statements (and if-else, else-if chains, and nested ifs). Repetition means your algorithm performs a step multiple times. In Java, repetition is implemented with loops (while, for, and enhanced for).
Why this matters: AP Computer Science A isn’t just about knowing Java syntax—it’s about being able to trace and reason about how an algorithm’s control flow changes based on conditions. Many exam questions test whether you can predict what code does when different conditions are true or false.
How selection and repetition work together
Selection and repetition often combine in patterns like:
- Input validation: Keep asking for input while it’s invalid (repetition), and decide whether it’s valid using a condition (selection).
- Search: Repeatedly examine items, and if you find the target, take a special action.
- Counting with rules: Loop through data and increment counters only when certain conditions hold.
The key concept underneath both selection and repetition is the Boolean expression—an expression that evaluates to true or false. Conditions control whether an if block runs and whether a loop continues.
Example: repetition controlled by a Boolean condition
You don’t need to memorize lots of loop patterns in this section, but you do need to recognize the role of Boolean conditions.
int x = 1;
while (x < 5) {
System.out.println(x);
x++;
}
- The loop repeats while the condition
x < 5istrue. - Once
xbecomes5,x < 5isfalse, and the loop stops.
A common conceptual error is thinking the loop “runs 5 times because 5 is in the condition.” It actually runs based on the truth value of the condition each time it is checked.
Exam Focus
- Typical question patterns:
- Trace code that uses
ifconditions inside loops (e.g., “How many times is this printed?”). - Determine which inputs cause a loop to stop or continue based on a Boolean test.
- Predict final values of counters/variables after conditional updates.
- Trace code that uses
- Common mistakes:
- Forgetting that loop/
ifconditions are re-evaluated each time control reaches them. - Confusing assignment (
=) with comparison (==) when reading conditions. - Off-by-one reasoning errors (e.g., misunderstanding when
x < 5becomes false).
- Forgetting that loop/
Boolean Expressions
A Boolean expression is any expression in Java that evaluates to a boolean value: true or false. Booleans are the foundation of decision-making in code because every if statement and every loop condition depends on one.
Why this matters: You can write perfectly valid Java code that still behaves incorrectly if your Boolean expressions don’t match the logic you intended. On the AP exam, many questions are essentially “Do you understand what this condition really means?”
Where Boolean values come from
You can get a boolean value from:
- Boolean literals:
true,false - Boolean variables:
boolean isFinished = false;
- Relational comparisons (compare numbers/characters):
<,<=,>,>===,!=
- Logical operators applied to booleans:
&&(and),||(or),!(not)
- Method calls that return boolean (common with
Stringand other objects):str.equals("hi")returnstrueorfalse
Relational operators (comparisons)
Relational operators compare two values and produce a boolean result.
int score = 82;
boolean passed = score >= 60; // true
Important details:
- With primitive types like
int,double, andchar,==compares actual values. - With objects (like
String),==compares whether two references point to the same object, not whether they have the same characters. ForStringcontent comparison, you almost always want.equals(...).
String a = new String("cat");
String b = new String("cat");
System.out.println(a == b); // usually false (different objects)
System.out.println(a.equals(b)); // true (same characters)
This is a classic AP CSA misconception: students use == for strings and get surprising results.
Logical operators (combine or modify conditions)
Java’s main logical operators are:
- NOT:
!conditionflipstruetofalseandfalsetotrue. - AND:
A && Bis true only if both A and B are true. - OR:
A || Bis true if at least one of A or B is true.
These operators let you write conditions closer to how you think about rules in real life—“if the password is correct and the account is active…”, “if the user is an admin or a moderator…”.
Operator precedence (what gets evaluated first)
When multiple operators appear in a single expression, Java applies a precedence order. A practical subset you should rely on:
- Parentheses
(...) - NOT
! - Relational operators
< <= > >= - Equality
== != - AND
&& - OR
||
Even when you know precedence, using parentheses can prevent mistakes and make your intent clearer.
Exam Focus
- Typical question patterns:
- Evaluate the result of Boolean expressions for given variable values.
- Identify whether a condition is true/false for specific inputs.
- Distinguish
==vs.equals()in string/object comparisons.
- Common mistakes:
- Using
=instead of==when reading/writing conditions. - Using
==to compareStringcontents instead of.equals(). - Misreading precedence in expressions like
a > b && b > c(or forgetting parentheses when needed).
- Using
If Statements and Control Flow
An if statement is a selection structure that runs a block of code only when its condition is true.
Why this matters: Control flow is how your program “decides what to do next.” The hardest part for many learners is not writing an if, but predicting exactly which lines run and which lines are skipped—especially with nesting, missing braces, or multiple conditions.
The basic structure
if (condition) {
// runs only if condition is true
}
The parentheses must contain a boolean expression. Unlike some languages, Java does not treat 0/1 as false/true—your condition must actually be boolean.
What “control flow” means in practice
When Java executes an if statement:
- It evaluates the condition to either
trueorfalse. - If
true, it executes the body (the statement or block after theif). - If
false, it skips the body. - Execution continues with the next statement after the
ifblock.
Braces and single-statement bodies
Braces { } define a block—multiple statements treated as one unit.
If you omit braces, the if controls only the next single statement:
if (x > 0)
System.out.println("positive");
System.out.println("done");
Here, "done" prints regardless of x. This is a common bug when you intend both prints to be conditional.
Nested if statements
You can put an if inside another if to represent decisions that depend on earlier decisions.
Conceptually: you’re refining the path—“If the user is logged in, then check whether they are an admin.”
if (loggedIn) {
if (isAdmin) {
System.out.println("admin panel");
}
}
The “dangling else” idea (why indentation isn’t enough)
Java pairs an else with the closest previous unmatched if. Indentation doesn’t matter to the compiler—only braces do.
If you ever feel unsure about which if an else belongs to, add braces. That both clarifies meaning and prevents exam-trace mistakes.
Example: tracing an if statement
int temperature = 72;
if (temperature > 80) {
System.out.println("hot");
}
System.out.println("end");
Output:
temperature > 80is false, so"hot"is skipped."end"always prints.
Exam Focus
- Typical question patterns:
- Trace which statements execute given values (often with nested
ifs). - Determine final variable values after conditional updates.
- Identify the effect of missing braces.
- Trace which statements execute given values (often with nested
- Common mistakes:
- Assuming indentation changes behavior (it doesn’t).
- Forgetting that without braces only the next statement is controlled.
- Mis-pairing an
elsewith the wrongifwhen braces are missing.
If-Else Statements
An if-else statement is a two-way selection structure: exactly one of two paths runs.
Why this matters: Many real rules are naturally two-way—either you meet a condition or you don’t. if-else is also essential for writing mutually exclusive logic, where you want one outcome, not potentially many.
Basic structure
if (condition) {
// runs if condition is true
} else {
// runs if condition is false
}
The key idea: the else block is not “optional extra code”—it’s the alternative path.
Else-if chains (multi-way selection)
When you have more than two cases, you often use an else-if chain:
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else if (score >= 70) {
grade = "C";
} else {
grade = "F";
}
How it works:
- Conditions are checked top to bottom.
- The first true condition’s block executes.
- The rest of the chain is skipped.
This ordering is not a style detail—it’s part of the logic. If you reorder these tests incorrectly, you can make later cases unreachable.
For example, if you start with if (score >= 70) then scores of 90 would match that first condition, and you’d never reach the A case.
Choosing between separate ifs and an if-else chain
Separate if statements are appropriate when multiple independent actions might occur.
if (x > 0) { System.out.println("positive"); }
if (x % 2 == 0) { System.out.println("even"); }
Both could print.
An if-else-if chain is appropriate when you want exactly one category.
Example: avoiding overlapping cases
Suppose you want to label a number as negative, zero, or positive:
if (n < 0) {
System.out.println("negative");
} else if (n == 0) {
System.out.println("zero");
} else {
System.out.println("positive");
}
This guarantees one label.
A common mistake would be writing three separate ifs, which would still work here (since the conditions are mutually exclusive), but in many problems conditions overlap and you might accidentally print multiple labels.
Exam Focus
- Typical question patterns:
- Determine which branch executes in an if-else or else-if chain.
- Identify unreachable code or redundant conditions in an else-if chain.
- Predict outputs when conditions overlap.
- Common mistakes:
- Putting conditions in the wrong order so earlier tests “steal” later cases.
- Using multiple separate
ifs when the situation requires mutually exclusive behavior. - Forgetting that exactly one branch of an
if-elseruns (never both).
Compound Boolean Expressions
A compound Boolean expression combines simpler boolean expressions using logical operators like &&, ||, and !.
Why this matters: Most interesting program rules aren’t single comparisons. You often need to express things like “in range,” “valid input,” or “allowed access,” which require combining conditions. AP CSA frequently tests whether you understand how compound expressions evaluate, including short-circuit behavior and negation.
AND (&&): requiring multiple conditions
Use && when all conditions must be true.
A classic pattern is a range check:
if (age >= 13 && age <= 19) {
System.out.println("teen");
}
This reads like English: age is at least 13 and at most 19.
OR (||): allowing alternative conditions
Use || when any one condition being true is enough.
if (day.equals("Sat") || day.equals("Sun")) {
System.out.println("weekend");
}
NOT (!): reversing a condition
! flips the truth value:
if (!isEmpty) {
// runs when isEmpty is false
}
A common readability issue is double negatives such as if (!notReady). You can often simplify by renaming variables (e.g., isReady) or rewriting the logic.
Short-circuit evaluation (very important in Java)
Java uses short-circuit evaluation for && and ||:
- For
A && B: ifAis false, Java does not evaluateB. - For
A || B: ifAis true, Java does not evaluateB.
Why this matters:
- It can improve efficiency (skip unnecessary checks).
- It can prevent runtime errors by guarding a risky expression.
Example: guarding against division by zero
if (denominator != 0 && numerator / denominator > 2) {
System.out.println("large ratio");
}
If denominator is 0, the left side is false, so Java skips the division and avoids an ArithmeticException.
Another common guard is checking for null before calling a method:
if (name != null && name.length() > 0) {
System.out.println(name);
}
If name is null, Java skips name.length() and prevents a NullPointerException.
Mixing && and || (use parentheses to control meaning)
When expressions get more complex, parentheses matter. Consider:
if (isMember || isEmployee && hasCoupon) {
// ...
}
Because && has higher precedence than ||, this is interpreted as:
isMember || (isEmployee && hasCoupon)
If you meant:
(isMember || isEmployee) && hasCoupon
…you must add parentheses.
Worked example: tracing a compound expression
int x = 5;
int y = 10;
boolean result = (x < 0) || (y / x > 1);
System.out.println(result);
Step-by-step:
- Evaluate
(x < 0)→5 < 0isfalse. - Because it’s
||, Java must evaluate the right side (left side wasn’t true). - Evaluate
(y / x > 1)→10 / 5is2, and2 > 1istrue. false || true→trueprints.
If x had been 0, then the division would be dangerous. You’d rewrite the condition as a guarded check, for example:
boolean safe = (x != 0) && (y / x > 1);
Exam Focus
- Typical question patterns:
- Evaluate compound expressions for given values (including precedence).
- Determine whether a risky right-hand expression is evaluated (short-circuit reasoning).
- Rewrite conditions to correctly represent rules like “in range” or “not in range.”
- Common mistakes:
- Forgetting short-circuit behavior and assuming both sides always evaluate.
- Mixing
&&and||without parentheses, leading to unintended logic. - Writing impossible range checks like
x > 10 && x < 5(always false).
Equivalent Boolean Expressions
Two Boolean expressions are equivalent if they produce the same true/false result for all possible inputs. In other words, they represent the same logical rule even if they look different.
Why this matters: On the AP exam, you’re often asked to simplify logic, correct conditions, or identify which expression matches a described behavior. In real coding, recognizing equivalence helps you write clearer conditions, avoid bugs, and correctly negate conditions.
De Morgan’s Laws (the most tested equivalences)
De Morgan’s Laws describe how negation distributes over && and ||:
!(A && B)is equivalent to(!A || !B)!(A || B)is equivalent to(!A && !B)
These are essential when you need to rewrite a negated compound condition.
Example: negating a range check
Suppose you have:
boolean inRange = (x >= 0 && x <= 10);
What does “not in range” mean?
- Start with the negation:
!(x >= 0 && x <= 10) - Apply De Morgan’s Law:
x < 0 || x > 10
So you can write:
boolean outOfRange = (x < 0 || x > 10);
A common mistake is to negate each comparison but keep &&, producing x < 0 && x > 10, which can never be true.
Negating comparisons correctly
Negating a simple comparison flips the operator:
| Original | Negation |
|---|---|
x < y | x >= y |
x <= y | x > y |
x > y | x <= y |
x >= y | x < y |
x == y | x != y |
x != y | x == y |
This becomes powerful when combined with De Morgan’s Laws.
Rewriting to improve clarity (without changing meaning)
Even when two expressions are equivalent, one may be easier to understand.
Example: avoid an unnecessary negation
if (!(count == 0)) {
// ...
}
Equivalent, clearer version:
if (count != 0) {
// ...
}
Example: express “between” as a range
Instead of:
if (x > 3 && x < 7) {
// ...
}
This is already clear, but if you see the longer form:
if (!(x <= 3 || x >= 7)) {
// ...
}
You should recognize it as the same idea (inside the interval).
Using truth tables (conceptual tool)
A truth table lists all possible truth values of component conditions and the resulting truth value of the full expression. You usually don’t need to draw full truth tables on AP CSA, but the reasoning style is helpful:
- If two expressions match for every possible combination of inputs, they are equivalent.
- If you find even one case where they differ, they are not equivalent.
Example: spotting a common equivalence
Consider the statement: “The student does NOT have both missing homework and a failing test.”
Let:
A= missing homeworkB= failing test
“NOT (A AND B)” is:
!(A && B)
By De Morgan, this is equivalent to:
(!A || !B)
In words: either they are not missing homework, or they are not failing the test (or both). That matches “it is not the case that both problems happen simultaneously.”
Equivalence pitfalls in programming context
Equivalence is about logic, but code adds a practical twist: side effects and short-circuiting.
For example, these are logically equivalent:
!(A && B)(!A || !B)
But if A or B includes a method call that changes state (side effect), the two versions might call methods in different patterns due to short-circuiting. On AP CSA, conditions are typically free of side effects, but it’s still good practice to keep conditions simple and avoid embedding work inside them.
Exam Focus
- Typical question patterns:
- Choose which expression is equivalent to a given one (often using De Morgan’s Laws).
- Rewrite a condition to represent “not (something)” correctly.
- Identify which rewritten condition correctly describes a range or category.
- Common mistakes:
- Negating each comparison but forgetting to switch
&&and||(De Morgan’s Laws). - Incorrectly negating operators (e.g., thinking
!(x < 5)becomesx <= 5instead ofx >= 5). - Creating impossible conditions when describing “outside a range” (using
&&instead of||).
- Negating each comparison but forgetting to switch