Switch Statements and the Ternary Operator
Cleaner alternatives for multi-branch decisions
After this lesson, you will be able to:
- Write switch statements using both traditional (
case:/break) and modern arrow (->) syntax - Identify and avoid fall-through bugs in traditional switch statements
- Use switch expressions to assign values directly to variables
- Apply the ternary operator for simple conditional assignments
- Decide when to use switch, if-else-if, or the ternary operator
Press 1 for English, 2 for Spanish…
You have written if-else-if chains. They work. But picture a phone menu: “Press 1 for English, 2 for Spanish, 3 for French, 4 for German, 5 for Mandarin.” An if-else-if chain checking the same variable against five exact values gets tedious fast. There is a better tool for this job: the switch statement.
And sometimes you just need a quick one-liner: “If the user is 18 or older, set the label to Adult; otherwise, Minor.” A full if-else block feels heavy for that. The ternary operator handles it in a single expression.
This lesson covers both tools, when to reach for them, and when to stick with if-else.
The Traditional Switch Statement
The traditional switch tests one variable against a list of exact values:
int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
case 4:
System.out.println("Thursday");
break;
case 5:
System.out.println("Friday");
break;
default:
System.out.println("Weekend or invalid");
}
// Output: Wednesday
Here is how it works:
- Java evaluates the expression in parentheses (
day) once. - It compares the result against each
caselabel, top to bottom. - When it finds a match, it executes the code after that label.
breakexits the switch. Without it, execution keeps going into the next case.defaulthandles any value that does not match.
Key Insight: Each
caselabel must be a compile-time constant — a literal number, character, or string. You cannot use variables or method calls as case labels.
Fall-Through: The Classic Trap
Forget a break and Java silently continues into the next case. This is called fall-through, and it is the number one switch bug:
int day = 2;
switch (day) {
case 1:
System.out.println("Monday");
// missing break!
case 2:
System.out.println("Tuesday");
// missing break!
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Other");
}
// Output:
// Tuesday
// Wednesday
When day is 2, Java matches case 2 and prints “Tuesday.” But there is no break, so it falls through to case 3 and prints “Wednesday” before finally hitting break.
Common Pitfall: Missing
breakis inherited from C (1972) and was originally considered a feature. In practice, it causes far more bugs than it solves. Always includebreakin traditional switch unless you deliberately want fall-through.
Intentional Fall-Through: Grouping Cases
The one legitimate use of fall-through is grouping cases that share the same code:
int month = 3;
int days;
switch (month) {
case 1: case 3: case 5: case 7:
case 8: case 10: case 12:
days = 31;
break;
case 4: case 6: case 9: case 11:
days = 30;
break;
case 2:
days = 28; // ignoring leap years
break;
default:
days = -1; // invalid month
}
Months 1, 3, 5, 7, 8, 10, and 12 all fall through to days = 31. This works, but it is still easy to misread. Modern syntax solves this more cleanly.
What does this code print?
int x = 1;
switch (x) {
case 1:
System.out.print("A");
case 2:
System.out.print("B");
break;
case 3:
System.out.print("C");
}
Modern Arrow Syntax (Java 14+)
Modern Java replaces the colon-break pattern with arrow syntax (->):
int day = 3;
switch (day) {
case 1 -> System.out.println("Monday");
case 2 -> System.out.println("Tuesday");
case 3 -> System.out.println("Wednesday");
case 4 -> System.out.println("Thursday");
case 5 -> System.out.println("Friday");
default -> System.out.println("Weekend or invalid");
}
// Output: Wednesday
The arrow syntax has three advantages over the traditional form:
- No fall-through. Each case is independent. No
breakneeded. - Cleaner. Less boilerplate, easier to scan.
- Safer. The most common switch bug is eliminated entirely.
The Trick: Use arrow syntax for all new code in this course. You need to recognize the traditional syntax because it appears in textbooks, older projects, and exam questions. But when you write new switch statements, use
->.
Grouping Cases with Commas
Multiple values can share a single arrow case:
int month = 3;
int days = switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> 31;
case 4, 6, 9, 11 -> 30;
case 2 -> 28;
default -> -1;
};
Compare this to the traditional fall-through version above. The comma-separated cases are dramatically cleaner.
Switch Expressions: Returning Values
With arrow syntax, a switch can be an expression that produces a value:
int day = 5;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> "Invalid day";
};
System.out.println(dayName); // Friday
Notice the semicolon after the closing brace. The entire switch is an expression assigned to dayName, so it ends with ; like any other assignment statement.
Multi-Statement Cases with yield
When a case needs more than one line, use braces and the yield keyword to return a value:
String category = switch (score / 10) {
case 10, 9 -> {
System.out.println("Excellent work!");
yield "A";
}
case 8 -> {
System.out.println("Good job!");
yield "B";
}
default -> {
System.out.println("Keep trying!");
yield "Below B";
}
};
Key Insight:
yieldexits the switch expression and provides its value.returnexits the entire method. Do not confuse them. Useyieldinside switch expressions; usereturnto exit methods.
What Types Can You Switch On?
| Type | Allowed? | Notes |
|---|---|---|
int, byte, short, char |
Yes | The original supported types |
String |
Yes | Since Java 7 (uses .equals() internally) |
enum |
Yes | Type-safe; compiler checks all cases |
double, float |
No | Floating-point comparison is unreliable |
boolean |
No | Only two values — use if-else |
long |
No | Too many possible values |
Common Pitfall: String matching in switch is case-sensitive.
"Medium"does not matchcase "medium". Normalize input before switching:String size = userInput.toLowerCase();
When to Use Switch vs. If-Else-If
| Situation | Best choice | Why |
|---|---|---|
| Exact values (1, 2, 3, …) | switch |
Cleaner, potentially faster |
| Ranges (0–59, 60–69, …) | if-else-if |
Switch cannot handle ranges |
Complex boolean logic (&&, ||) |
if-else |
Switch cannot express compound conditions |
| String matching against known values | switch |
Clean since Java 7 |
| Only two paths | if-else |
Switch is overkill |
The Trick: Ask yourself: “Am I testing one variable against specific values?” If yes, use switch. If you are testing ranges, combining conditions, or comparing multiple variables, use if-else.
Which scenario is best suited for a switch statement?
From CSCD 110: Python 3.10 introduced
match-case, which is conceptually similar to Java’s switch:
Python 3.10+ Java (arrow syntax) match day:switch (day) {` case 1: |case 1 ->`` case _: |default ->`If you used
match-casein CSCD 110, the idea transfers directly. If you used if-elif chains instead, think of switch as a specialized shorthand for checking one variable against many exact values.
Complete Example: Day-of-Week Planner
Putting it together, here is a program that reads a day number and prints the day name along with a suggested activity:
import java.util.Scanner;
void main() {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter day number (1-7): ");
int day = scanner.nextInt();
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> "Invalid";
};
String activity = switch (day) {
case 1, 3, 5 -> "Lecture day -- review notes before class.";
case 2, 4 -> "Lab day -- start early, ask questions.";
case 6 -> "Catch up on reading and practice problems.";
case 7 -> "Rest. Seriously. You need it.";
default -> "Not a valid day number.";
};
if (!"Invalid".equals(dayName)) {
System.out.println(dayName + ": " + activity);
} else {
System.out.println("Please enter a number between 1 and 7.");
}
}
This uses two switch expressions: one to look up the day name, one to look up the activity. Both use arrow syntax with comma-grouped cases. The default branch handles invalid input.
The Ternary Operator
The ternary operator is a one-line if-else expression:
condition ? valueIfTrue : valueIfFalse
int age = 20;
String status = (age >= 18) ? "Adult" : "Minor";
System.out.println(status); // Adult
This is exactly equivalent to:
String status;
if (age >= 18) {
status = "Adult";
} else {
status = "Minor";
}
The ternary version is shorter and often clearer for simple assignments.
Good Uses
// Maximum of two values
int max = (a > b) ? a : b;
// Singular vs. plural label
String label = (count == 1) ? "item" : "items";
System.out.println(count + " " + label);
// Absolute value (manual)
int abs = (x >= 0) ? x : -x;
Each of these is a straightforward, one-value assignment. The ternary reads naturally.
When NOT to Use the Ternary
// BAD: nested ternary is unreadable
String result = (x > 0) ? (y > 0) ? "Both+" : "Only x+" : "x-";
// GOOD: use if-else for anything complex
String result;
if (x > 0 && y > 0) {
result = "Both+";
} else if (x > 0) {
result = "Only x+";
} else {
result = "x-";
}
Key Insight: Use the ternary operator for simple, one-value assignments. If the condition or the values are complex, or if you need to do more than assign a single value, use if-else. The goal is readability, not brevity. Nested ternaries are a code smell that make debugging miserable.
Complete Example: Simple Calculator
This program combines switch expressions, the ternary operator, and input handling:
import java.util.Scanner;
void main() {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter first number: ");
double a = scanner.nextDouble();
System.out.print("Enter operator (+, -, *, /): ");
String op = scanner.next();
System.out.print("Enter second number: ");
double b = scanner.nextDouble();
// Validate division by zero
if (op.equals("/") && b == 0) {
System.out.println("Error: cannot divide by zero");
return;
}
String result = switch (op) {
case "+" -> a + " + " + b + " = " + (a + b);
case "-" -> a + " - " + b + " = " + (a - b);
case "*" -> a + " * " + b + " = " + (a * b);
case "/" -> a + " / " + b + " = " + (a / b);
default -> "Unknown operator: " + op;
};
// Ternary to choose output label
String label = ("Unknown operator: ".equals(result.substring(0, Math.min(19, result.length()))))
? "Error"
: "Result";
System.out.println(label + ": " + result);
}
The switch expression maps each operator to a formatted result string. Division by zero is validated before the switch. The default case handles invalid operators.
Which use of the ternary operator is appropriate?
What is wrong with this code?
String size = "medium";
double price = switch (size) {
case "small" -> 2.00;
case "medium" -> 3.00;
case "large" -> 4.00;
}
Decision Tool Summary
You now have four tools for making decisions in Java. Here is when to reach for each one:
| Tool | Best for | Avoid when |
|---|---|---|
if-else |
Two paths, range checks, compound conditions | You are checking one variable against many exact values |
if-else-if |
Ordered ranges, complex boolean logic | A switch would be cleaner |
switch (arrow) |
One variable, multiple exact values | You need ranges or compound conditions |
Ternary ? : |
Simple one-value assignments | The logic is complex or nested |
Big Picture: Switch statements appear throughout real-world programming: menu systems, command dispatchers, protocol handlers. In CSCD 211, you will use switch with enums to represent object states. In CSCD 260 (Computer Organization), the switch concept maps directly to a jump table — a hardware-optimized lookup that the CPU uses to dispatch operations in constant time.
Summary
Switch statements replace long if-else-if chains when you are testing one variable against exact values. The traditional syntax (case:/break) requires break to prevent fall-through — the most common switch bug. Modern arrow syntax (->) eliminates fall-through entirely and can return values as a switch expression. Use arrow syntax for all new code.
The ternary operator (condition ? a : b) is a one-line if-else expression for simple assignments. It is not a replacement for if-else — it is a shortcut for the narrow case where you need to pick one of two values based on a condition. Never nest ternaries.
Next up: Loops — while, for, and do-while. Loops combined with conditionals let you retry invalid input, process collections of data, and build interactive programs that run until the user says “quit.”