Switch Statements
A switch expression computes and returns a single value, so it is used when the purpose of a switch is to produce a value for an assignment or another expression.
Watching a Switch Choose a Value
A switch is a way to choose between several possible outcomes based on one value. This article follows a traced run of a small program that chooses a value and stores it in a variable. As you read, keep two questions in mind: which case the switch chose, and what value ended up in the variable. Most of the rules in this article come from one observation: a switch expression is part of an assignment, so the value it computes is the value that gets stored.
What do you think happens?
Before reading on, what does the variable size hold after this code runs?
Reveal answer
medium
The controlling expression count holds 4. The case labeled 3, 4 matches that value, so its result "medium" becomes the value of the switch expression, and the assignment stores it in size.
medium- count holds 4, so the entry with the label 3, 4 is chosen
- the chosen entry's expression is the value of the whole switch
- the assignment stores that value in size
- the default entry would supply large for any value no earlier case matches
Expression Versus Statement
A switch statement tests one expression and jumps to the case label that matches its value. A switch expression also chooses a case, but it computes and returns a single value, so it is used when the purpose of the switch is to produce a value for an assignment or another expression. Many switch statements exist for one purpose: to assign a value to a variable, where the value depends on which case matched. The expression form handles that pattern more directly.
| Feature | Switch statement | Switch expression |
|---|---|---|
| Main purpose | Performs actions by jumping to a position | Computes a single value |
| What each case holds | A statement | An expression or a throw statement |
| Can sit where a value is expected | No | Yes, for example on the right side of an assignment or inside a print call |
| Must always produce a result | Not required | Yes, or it throws an exception, which is why a default case is usually included |
Comparing a switch statement with a switch expression, based on the source's description of each form.
Reading the Switch Expression Template
Read the template from left to right. The variable on the left receives the result. The keyword switch is followed by the controlling expression in parentheses. Each case has a value, an arrow, and then an expression that gives the result for that case. The default case covers any value not matched by an earlier case. The closing brace is followed by the semicolon that ends the assignment.
In the anatomy above, the case values are the labels that the controlling expression is compared against. The result expressions are the values the switch produces when that case is chosen. The default entry is the fallback. The source explains that each case holds an expression rather than a statement, which is why the arrow form separates each case's value from the result it produces.
Yield and Blocks in a Switch Expression
Sometimes a case needs more than one step before it can produce its value. In that situation, the expression in the case can be replaced by a block containing several statements. The block itself does not produce the switch's value. Instead, the value is specified by a yield statement, such as yield 42. The value after the word yield is returned as the value of the switch expression. Only the case that was chosen runs, so only its yield determines the result.
Following a yield through a block case
An int named code holds 2. A switch expression assigns its result to a String named text. Case 2 is a block that declares String part equal to "ab" and then yields part followed by "!". Find the value of text.
- 1Identify the controlling value
code holds 2, so control moves to the entry for case 2.
- 2Run the block
The block declares part and sets it to "ab". No value leaves the switch yet, because a block does not produce the result by itself.
- 3Find the yield
The yield statement's value is part followed by "!", which is "ab!".
- 4Leave the switch
The value after yield becomes the value of the switch expression, and no other case runs.
- 5Store the result
The assignment stores "ab!" in text.
text holds "ab!"
Finding the Case Behind an Unexpected Value
When a switch expression produces a surprising value, the useful question is which case was chosen and what that case produced. In the traced run, the divergence point is the case that was actually selected, not the variable that was assigned. The assignment only stores what the switch returned, so a wrong stored value usually traces back to a case expression or a yield value that was not the one you expected.
- 1Start with the controlling expression and evaluate it to a single value.
- 2Find the case whose label contains that value. Check every label, including comma-separated lists.
- 3If the chosen case is a single expression, that expression is the result.
- 4If the chosen case is a block, look for its yield statement and evaluate the value after yield.
- 5If no case matches, the default case supplies the result.
Switch expressions are not limited to assignment statements. Because they compute a value, you can use one anywhere another expression could be used, such as inside an output statement. The same tracing steps apply in that case: find the chosen entry, then find the value it produces.
Other- no variable holds the switch's value
- day is 5, and no listed case matches it
- the default case supplies Other, which is passed directly to println
Which Types a Switch Can Test
A switch statement only accepts expressions of certain types. The value of the expression can be one of the primitive integer types int, short, or byte. It can be the primitive char type. It can be String. It can also be an enum type, which is a type whose values are named constants. The expression may not be double or float.
The positions a switch can jump to are marked with case labels. A case label takes the form case followed by a constant list. The constant list consists of one or more literals of the same type as the expression in the switch, separated by commas. The label is followed by an arrow, made of a hyphen and a greater-than character, and then a single statement. That statement can be a subroutine call statement, a throw statement, or a block statement containing several nested statements. A switch can also have at most one default entry in place of a case label, and all case constants must be different.
Fall-Through in the Traditional Colon Form
Java has two syntaxes for switch statements. The original syntax was modeled on the C programming language, and the source describes it as error-prone and somewhat awkward to read. It is still common in existing code, so you need to be able to read it. In this form, the code under one label keeps running until a break is reached. That is why an unexpected result can start at a case label and continue into the next one.
three- control jumps to the case 2 label
- word is set to two, but there is no break after it
- execution continues into the code under case 3
- the break after word = three is the first one reached
Read the flowchart as the trace of the program. Control jumps directly to the case 2 label because count is 2. The line word = two runs, but nothing stops execution there. The code under case 3 runs next, so word becomes three. The first break is reached after that, and then println prints three. The divergence point is the case 2 label, where control arrives. The missing break after word = two is what lets execution continue.
Traditional Versus Java 17 Syntax
| Aspect | Traditional colon syntax | Java 17 arrow syntax |
|---|---|---|
| Label form | case value: followed by statements | case value -> followed by one statement, expression, or block |
| Ending each case | A break is needed to stop fall-through | No break is needed, because the arrow selects one entry |
| Availability | Original syntax, still common in existing code | Requires Java 17 |
| Source's advice | Read it, because much existing code uses it | Use it when writing new code |
Traditional and Java 17 switch syntax, as described in the source.
This article follows the new syntax first, and the traditional form is treated later. Both forms rest on the same idea: a value selects a jump point. Learning the case label rules carefully therefore helps with either form.
Mistakes Beginners Make With Switches
Common mistake Expecting a switch expression to finish without a value
Why it failsA switch expression must always compute a value or throw an exception, so it usually includes a default case.
Do this insteadAdd a default entry that supplies a value for any input no other case matches.
Common mistake Thinking a block in a case produces the value
What it looks likecase 2 -> { String part = "ab"; part + "!"; }Why it failsThe block does not produce the switch's value. The value comes from a yield statement.
Do this insteadUse yield part + "!"; inside the block so that the value after yield leaves the switch.
Common mistake Forgetting break in the colon form
What it looks likecase 2: word = "two"; case 3: word = "three"; break;Why it failsWithout a break, execution continues into the code under the next label.
Do this insteadPlace a break after each case that should stop there, or switch to the arrow form in new code.
Common mistake Using a label whose literal type does not match the selector
Why it failsCase labels must be literals of the same type as the switch expression, and all case constants must be different.
Do this insteadCheck the selector type first, then write labels of that type and make sure no two are equal.
Common mistake Using double or float as the selector
Practice Tracing a Switch
An int named day holds 3. A switch expression with cases for 1, 2, and 3 assigns its result to a String named name. The case for 3 is a block that declares a local String named label, then yields label joined with the text day. Trace the switch and state which case was chosen, which line produces the value, and what the variable name holds after the assignment.
Hints
- Start with the controlling value 3 and find the matching case.
- The block does not give the result by itself. Look for the yield statement.
- The value after yield leaves the switch and is stored by the assignment.
A colon-form switch has cases 1, 2, and 3, and the code under case 1 sets a value without a break. If the selector holds 1, which case bodies run, and where does execution stop?
Hints
- Control jumps to the case 1 label.
- Without a break, execution falls through into the next label.
Key Takeaways
- A switch expression computes and returns a single value, so it is used when a switch must produce a value for an assignment or another expression.
- Each case in an arrow-form switch expression holds an expression or throw statement, and a case with a block gives its value through a yield statement.
- A switch selector may be int, short, byte, char, String, or an enum type, and case labels must use literals of the same type with no duplicates.
- When tracing a surprising result, find the chosen case first, then follow its expression or yield, and in the colon form watch for a missing break that causes fall-through.