SEN1001 · Week 3 · Control Statements: Part 1

Decision structures: if/else, logical operators, switch

if, else if chains, nested if, short-circuiting with &&, || and !, switch and fall-through. On the midterm it comes both as output tracing and as writing getSeason-style methods.

selection statementboolean expressionrelational operatorif...elsenested ifdangling elselogical operatorshort-circuit evaluationconditional operator (ternary)switchcasebreakfall-throughdefault

Until now the program ran every line from top to bottom. Decision structures (selection statements) let you run some lines and skip others depending on a condition. Two kinds of questions come up on the midterm: following the conditions to find what is printed, and writing short methods that say “return this for that value” (letter grade, month name, season).

Golden rules:

  1. In an else if chain the first true branch runs, and the rest are not looked at.
  2. Without curly braces an if covers a single statement. Indentation misleads.
  3. && and || short-circuit: once the result is known, the right side does not run at all.
  4. In a switch, without break it falls through (fall-through), default included.
  5. = is assignment, == is comparison. = inside an if does not compile.

Comparison and boolean expressions

Relational operators compare two values and produce a boolean (true/false).

OperatorMeaningwhen a = 7, b = 3
==equal?a == b → false
!=not equal?a != b → true
> <greater, lessa > b → true
>= <=greater or equal, less or equala <= 7 → true
int a = 7, b = 3;
System.out.println((a > b) + " " + (a == b) + " " + (a != b) + " " + (a <= 7));
boolean big = a > 5;
System.out.println(big);
true false true true
true

A boolean can be stored in a variable and printed directly.

PITFALL · a single equals sign inside an if. if (x = 5) does not compile: incompatible types: int cannot be converted to boolean. An if wants a boolean, and x = 5 is an assignment that produces an int.

if and if-else

int temp = 12;
if (temp > 25) {
    System.out.println("Sicak");
} else {
    System.out.println("Serin");
}
System.out.println("Bitti");
Serin
Bitti

If the condition is true, the if block runs; if it is false, the else block runs. Exactly one of the two runs. The lines after the block (Bitti) run in every case.

The else if chain

When there are several ranges, you use else if. Java tries the conditions from top to bottom, runs the first true one, and skips the rest of the chain.

public static String letter(int score) {
    if (score >= 90) return "A";
    else if (score >= 80) return "B";
    else if (score >= 70) return "C";
    else if (score >= 60) return "D";
    else return "F";
}

Calls letter(85), letter(90), letter(59):

B A F

When we reach the score >= 80 branch for 85, we already know score < 90; so there is no need to write score >= 80 && score < 90.

PITFALL · wrong order. If you start the chain from the small end, like if (score >= 60) return "D"; else if (score >= 70) ..., even a student with 95 gets a D, because the first true condition is >= 60. During verification letterWrongOrder(95) really returned D. When you work with lower bounds, order them from largest to smallest.

A chain and separate ifs are different:

int s = 95;
if (s >= 90) System.out.print("A ");
if (s >= 80) System.out.print("B ");
if (s >= 70) System.out.print("C ");
A B C 

Three separate ifs, all three are checked independently and all three are true.

Curly brace and semicolon traps

int x = -2, cnt = 0, other = 0;
if (x > 0)
    cnt++;
    other++;          // the indentation misleads: this line is OUTSIDE the if
System.out.println(cnt + " " + other);
int y = -5;
if (y > 0);           // the ; at the end is an empty statement, it is the if's body
{
    System.out.println("pozitif?");
}
0 1
pozitif?

In the second example the body of the if is that empty semicolon. The curly brace block below has nothing to do with the if and always runs. pozitif? was printed even though y is negative.

Dangling else

int m = 5, n = 20;
if (m > 10)
    if (n > 10)
        System.out.println("ikisi de buyuk");
else
    System.out.println("else kime ait?");
System.out.println("son");
son

An else always belongs to the nearest unmatched if: here the inner if (n > 10). The indentation makes it look as if it belonged to the outer if, but Java does not look at indentation. Because the outer condition is false, nothing inside ran. The way to avoid this: always use { }.

Logical operators

aba && b (AND)a || b (OR)!a (NOT)
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue

Precedence: first !, then &&, last ||. Comparisons are done before these, which is why age >= 18 && student works without parentheses.

int age = 20;
boolean student = true;
System.out.println(age >= 18 && student);
System.out.println(age < 18 || !student);
System.out.println(!(age == 20));
System.out.println(true || false && false);     // && first: true || false
System.out.println((true || false) && false);
true
false
false
true
false

Short-circuit evaluation

  • &&: if the left side is false, the result is already false, and the right side is not looked at.
  • ||: if the left side is true, the result is already true, and the right side is not looked at.

This is used as a guard:

int d = 0;
if (d != 0 && 10 / d > 1) System.out.println("buyuk");
else System.out.println("guvenli");
guvenli

Because d != 0 is false, 10 / d was never computed and the program did not crash. If you had written the order the other way round (10 / d > 1 && d != 0) you would get an ArithmeticException.

If the right side has a side effect like ++z, short-circuiting means that side effect never happens. The midterm sets exactly this trap.

The conditional operator (ternary)

condition ? value1 : value2 is a short if-else; it produces a value.

int t1 = 8;
String parity = (t1 % 2 == 0) ? "even" : "odd";
System.out.println(parity);
even

switch

You use switch to branch on specific values of a variable. It works with int, char, String (and byte, short); it cannot be written with double or boolean.

int day = 3;
switch (day) {
    case 1: System.out.println("Mon"); break;
    case 2: System.out.println("Tue"); break;
    case 3: System.out.println("Wed"); break;
    default: System.out.println("Other");
}
Wed

The rule: Java jumps to the matching case, starts running downward from there, and continues until it sees a break. If no case matches, default runs (like else). default is not required.

Fall-through

int lvl = 2;
switch (lvl) {
    case 1: System.out.println("one");
    case 2: System.out.println("two");
    case 3: System.out.println("three");
    default: System.out.println("default");
}
two
three
default

It entered at case 2, and because there was no break, everything below ran, default included. case 1 stayed above, so it did not run: a switch never goes above the matching case.

Fall-through is also used on purpose: if several values do the same job, you write the cases one under another.

char g = 'B';
switch (g) {
    case 'A': case 'B': System.out.println("Iyi"); break;
    case 'C': System.out.println("Orta"); break;
    default: System.out.println("Zayif");
}
String cmd = "stop";
switch (cmd) {
    case "go": System.out.println("Gidiyor"); break;
    case "stop": System.out.println("Duruyor"); break;
    default: System.out.println("?");
}
Iyi
Duruyor

switch inside a method: with return

If the method returns a value, you write return in every case. Because return ends the method immediately, no break is needed. daysInMonth in the question bank above is an example of this pattern; the season, day name and letter grade questions are solved with the same skeleton.

Common mistakes

Wrong ideaThe truth
if (x = 5)if (x == 5); a single = does not compile
In else if, all true branches runOnly the first true branch
Indentation decides the scope of an ifWithout { } it is only one statement
if (x > 0); is harmlessEmpty body; the block below always runs
else belongs to the outer ifTo the nearest unmatched if
a || b && c goes left to right&& first: a || (b && c)
The ++z on the right of a condition always runsWith short-circuiting it never runs
switch runs the matching case and leavesWithout break it falls through
switch works with doubleIt does not; use int, char, String
Compare a String with ==equals; switch does this itself for Strings

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

What is printed?

int x = 15;
if (x > 10) System.out.println("A");
else if (x > 5) System.out.println("B");
else System.out.println("C");
Show answer
A

In an else if chain, the first true branch runs and the rest are not looked at. 15 > 10 is true → A. 15 > 5 is also true, but that branch is never reached.

Question 2medium

What is printed?

int x = 15;
if (x > 10) System.out.print("A");
if (x > 5) System.out.print("B");
else System.out.print("C");
System.out.println();
Show answer
AB

This time there are two separate ifs. The first if prints A. The second if is checked independently: 15 > 5 is true → B. The else belongs only to the second if, so it does not run.

Question 3easy

What is printed?

int a = 4, b = 9;
System.out.println(a > 3 && b < 5);
System.out.println(a > 3 || b < 5);
System.out.println(!(a > 3) || b % 3 == 0);
Show answer
false
true
true

1) true && false → false. 2) true || false → true. 3) !(true) = false; 9 % 3 == 0 is true; false || true → true.

Question 4medium

What is printed?

int x = 0;
if (x > 0)
    System.out.println("pos");
    System.out.println("checked");
Show answer
checked

Without curly braces, the if covers only the single statement right below it. Indentation means nothing to Java. The checked line is outside the if and always runs.

Question 5medium

What is printed when day is (a) 2, (b) 4, (c) 7?

switch (day) {
    case 1: System.out.println("Red");
    case 2: System.out.println("Green");
    case 3: System.out.println("Blue"); break;
    case 4: System.out.println("Black");
    default: System.out.println("White");
}
Show answer
(a) Green, Blue · (b) Black, White · (c) White

(a) Enter at case 2, there is no break → fall through to case 3 (fall-through), Blue, break → exit. (b) Enter at case 4, no break → falls into default: Black, White. (c) No case matches → only default: White. Each word is printed on its own line.

Question 6hard

What is printed?

int q = 3, z = 0;
if (q > 5 && ++z > 0) System.out.println("in");
System.out.println(z);
if (q < 5 || ++z > 0) System.out.println("in2");
System.out.println(z);
Show answer
0
in2
0

Short-circuit: if the left of && is false, it never looks at the right, so ++z does not run → z = 0. If the left of || is true, it does not look at the right, so again ++z does not run → z is still 0. Because the condition is true, in2 is printed.

Question 7hard

What is printed?

int a = 2, b = 8;
if (a > 5)
    if (b > 5)
        System.out.println("X");
else
    System.out.println("Y");
System.out.println("Z");
Show answer
Z

Dangling else: the else belongs to the nearest unmatched if, regardless of indentation, that is if (b > 5). Because the outer if (a > 5) is false, everything inside is skipped. Only Z is printed.

Question 8medium

What is printed?

int n = 7;
String res = (n > 5) ? (n > 10 ? "big" : "medium") : "small";
System.out.println(res);
Show answer
medium

The conditional operator (ternary) is condition ? a : b. 7 > 5 is true → look at the inner expression: 7 > 10 is false → "medium".

Question 9medium

What is printed?

String w = "B";
switch (w) {
    case "A": System.out.print("1 ");
    case "B": System.out.print("2 ");
    case "C": System.out.print("3 "); break;
    default: System.out.print("4 ");
}
Show answer
2 3

switch works with String too (it compares with equals). "B" matches → 2 , no break → 3 , break. default is never reached.

Question 10easy

What is printed?

int score = 72;
if (score >= 90) System.out.println("A");
if (score >= 70) System.out.println("C");
else if (score >= 60) System.out.println("D");
else System.out.println("F");
Show answer
C

The first if is independent and false. The second if starts a separate chain: 72 >= 70 is true → C, and the rest of the chain is skipped.

Question 11medium

Write a static method daysInMonth(int month) that uses a switch to return 28 for February, 30 for April, June, September and November, 31 for the other months, and -1 for an invalid month.

Show answer
public static int daysInMonth(int month) { switch (month) { ... } }

Write the cases that give the same result one under another (deliberate fall-through). Because return ends the method, no break is needed.public static int daysInMonth(int month) { switch (month) { case 2: return 28; case 4: case 6: case 9: case 11: return 30; case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; default: return -1; }}Test: daysInMonth(4) → 30, daysInMonth(7) → 31, daysInMonth(2) → 28, daysInMonth(13) → -1.

Question 12hard

Write a static method isLeapYear(int year): a year is a leap year if it is divisible by 4 but not by 100, or if it is divisible by 400. Use a single return statement.

Show answer
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;

Translate the rule word for word into logical operators. Although && has higher precedence than ||, writing parentheses improves readability.public static boolean isLeapYear(int year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;}Test: 2024 → true, 1900 → false (divisible by 100, not by 400), 2000 → true, 2026 → false.

Verification: All outputs were run with JDK 26 (verify/SEN1001/W03.java). The daysInMonth and isLeapYear methods were tested with several inputs. The if (x = 5) error was obtained by compiling verify/SEN1001/err/IfAssign.java with javac.

Review card

Comparison: == != < <= > >= result is boolean = assignment, == comparison if (x = 5) → does not compile (int cannot be converted to boolean) else if chain: the FIRST true branch runs, the rest are skipped → order: largest to smallest (>=90, >=80 ...) Separate ifs: each is checked independently Without { } the if covers only ONE statement; indentation does not matter if (x > 0); → the semicolon is an empty body, the block below ALWAYS runs else belongs to the nearest unmatched if (dangling else) && both true || one is enough ! the opposite precedence: ! → && → || Short-circuit: false && ... skips the right true || ... skips the right x != 0 && 10 / x > 1 → division by zero is guarded condition ? a : b switch: int, char, String (NOT double). From the matching case everything runs until break without break it falls down (fall-through), default included. If nothing matches, default case 12: case 1: case 2: return "Winter"; (deliberate fall-through)