Table of Contents
Java’s switch statement allows the comfortable selection of one of many execution paths based on a variable’s value. The variable must either be an enum, a String
, or an integral type like int
. Given to switch
, it is compared with a list of case
labels that each specify a value – as soon as the first one matches, the corresponding statement block is executed. The switch statement works much like a long if
–else
–if
chain and can often be used to replace it.
This article only requires working knowledge of integers and strings but the more you know about if
and particularly if
–else
–if
the more you will get out of it. Experience with other numeric types, enums and methods are a bonus.
Using switch
Let’s jump right in and start with an example! The following switch statement writes a textual representation of the first three natural numbers to the console:
// any number is fine
int number = 2;
switch (number) {
case 0:
System.out.println("zero");
break;
case 1:
System.out.println("one");
break;
case 2:
System.out.println("two");
break;
default:
System.out.println("many");
break;
}
Just from looking at it, what do you think will happen?
The switch will look at number
, which is currently 2
, and compare it with each of the values behind the case
keywords. It’s not 0
, it’s not 1
, it’s 2
. Bingo! So off it goes calling System.out.println("two")
.
Syntax of switch
You can use the switch
statement with variables of type int
, byte
, short
, char
(note that long
does not work), String
, or an enum (or enumeration type as they are formally called). Here’s how it works:
switch (<variable>) {
case <value>:
// statements
break;
case <other-value>:
// statements
break;
case <more-values>:
// statements
break;
default:
// statements
break;
}
You use the keyword switch
followed by the variable you want to switch over (as it is commonly phrased) and a pair of curly braces. Inside those curly braces, you list as many branches as you like.
Each regular branch consists of the keyword case
, a value that matches the variable’s type (meaning it could be assigned to it), and a colon. Together, these three things are called a switch label. It is followed by the statements you want to execute if the variable has that particular value. Unless you have a very good reason, every switch-branch should end in a break
. (I’ll explain in a minute, why.)
If you need a branch that is executed if none of the labels matched, you can create one with default
. It works much like a regular branch but takes no value.
Fall-Through
It is important to note that the switch statement does not only execute the matching branch. Instead it starts executing code at the matching label. If it does not hit a break
it will go right on into the next branch. This is called fall through and can be used intentionally.
The following statement starts counting at the given number:
// any number is fine
int number = 1;
switch (number) {
case 0:
System.out.println("zero");
// fall-through intended
case 1:
System.out.println("one");
// fall-through intended
case 2:
System.out.println("two");
// fall-through intended
default:
System.out.println("many");
}
In this case, the output is one two many
because number
matches 1
and switch executes all blocks because there are no breaks. The comment “fall-through intended” tells your fellow programmers that you did this on purpose and not just forgot to add the break
.
Return Inside switch
Many developers consider repeating break
ugly and try to push switches into methods, so that they can return a value. Because a return
ends execution of that method, there is no risk to fall through and hence no need for break
.
For the first example, the code might look as follows:
public String toEnglish(int number) {
switch (number) {
case 0: return "zero";
case 1: return "one";
case 2: return "two";
default: return "many";
}
}
Much shorter, isn’t it? Executing System.out.println(toEnglish(2))
would then print two
.
Other Types
I already mentioned that you can switch over more than just int
s. Other primitives that allow that are byte
, short
, and char
. You can also switch over they wrapper types Integer
, Byte
, Short
, and Character
but note that you will get a NullPointerException
if the variable is null
.
You can also switch over String
…
public int toNumber(String number) {
switch (number) {
case "zero": return 0;
case "one": return 1;
case "two": return 2;
default: throw new IllegalArgumentException();
}
}
… and enums.
public enum LittleNumber { ZERO, ONE, TWO }
public int toNumber(LittleNumber number) {
switch (variable) {
case ZERO: return "zero (0)";
case ONE: return "one (1)";
case TWO: return "two (2)";
default: return "unknown";
}
}
Summary
You learned how the switch statement is put together with the switch
keyword, labels (case
, a value, and a colon or default
and a colon) and code blocks. On the first match, the code is executed until it hits a break
, which might mean that it falls through into following branches. To keep switches short, it is common to put them into methods and return the results, thus avoiding breaks.
Armed with this knowledge, you can dive deeper. If you wonder why you can’t use long
, give this StackOverflow question a go. Also, you might soon wish there were ways to give the case
branches a little more expressiveness, for example by checking whether a numerical value is smaller than another. Then you’re thinking towards pattern matching, a feature Java does not yet support directly but may soon. Until then, library implementations can be a replacement and Javaslang has a good one.