OCP Oracle Certified Professional Java SE 17 Developer Study Guide. Jeanne Boyarsky
reasons, only the first and last
case
statements in the following example compile:
final int getCookies() { return 4; } void feedAnimals() { final int bananas = 1; int apples = 2; int numberOfAnimals = 3; final int cookies = getCookies(); switch(numberOfAnimals) { case bananas: case apples: // DOES NOT COMPILE case getCookies(): // DOES NOT COMPILE case cookies : // DOES NOT COMPILE case 3 * 5 : } }
The bananas
variable is marked final
, and its value is known at compile-time, so it is valid. The apples
variable is not marked final
, even though its value is known, so it is not permitted. The next two case
statements, with values getCookies()
and cookies
, do not compile because methods are not evaluated until runtime, so they cannot be used as the value of a case
statement, even if one of the values is stored in a final
variable. The last case
statement, with value 3 * 5
, does compile, as expressions are allowed as case
values, provided the value can be resolved at compile-time. They also must be able to fit in the switch
data type without an explicit cast. We go into that in more detail shortly.
Next, the data type for case
statements must match the data type of the switch
variable. For example, you can't have a case
statement of type String
if the switch
statement variable is of type int
, since the types are incomparable.
The switch Expression
Our second implementation of printDayOfWeek()
was improved but still quite long. Notice that there was a lot of boilerplate code, along with numerous break
statements. Can we do better? Yes, thanks to the new switch
expressions that were officially added to Java 14.
A switch
expression is a much more compact form of a switch
statement, capable of returning a value. Take a look at the new syntax in Figure 3.4.
Because a switch
expression is a compact form, there's a lot going on in Figure 3.4! For starters, we can now assign the result of a switch
expression to a variable result
. For this to work, all case
and default
branches must return a data type that is compatible with the assignment. The switch
expression supports two types of branches: an expression and a block. Each has different syntactical rules on how it must be created. More on these topics shortly.
FIGURE 3.4 The structure of a switch
expression
Like a traditional switch
statement, a switch
expression supports zero or many case
branches and an optional default
branch. Both also support the new feature that allows case
values to be combined with a single case
statement using commas. Unlike a traditional switch
statement, though, switch
expressions have special rules around when the default
branch is required.
->
is the arrow operator. While the arrow operator is commonly used in lambda expressions, when it is used in a switch
expression, the case
branches are not lambdas.
We can rewrite our previous printDayOfWeek()
method in a much more concise manner using case
expressions:
public void printDayOfWeek(int day) { var result = switch(day) { case 0 -> "Sunday"; case 1 -> "Monday"; case 2 -> "Tuesday"; case 3 -> "Wednesday"; case 4 -> "Thursday"; case 5 -> "Friday"; case 6 -> "Saturday"; default -> "Invalid value"; }; System.out.print(result); }
Compare this code with the switch
statement we wrote earlier. Both accomplish the same task, but a lot of the boilerplate code has been removed, leaving the behavior we care most about.
Notice that a semicolon is required after each switch
expression. For example, the following code does not compile. How many semicolons is it missing?
var result = switch(bear) { case 30 -> "Grizzly" default -> "Panda" }
The answer is three. Each case
or default
expression requires a semicolon as well as the assignment itself. The following fixes the code:
var result = switch(bear) { case 30 -> "Grizzly"; default -> "Panda"; };
As shown in Figure 3.4, case
statements can take multiple values, separated by commas. Let's rewrite our printSeason()
method from earlier using a switch
expression:
public void printSeason(int month) { switch(month) { case 1, 2, 3 -> System.out.print("Winter"); case 4, 5, 6 -> System.out.print("Spring"); case 7, 8, 9 -> System.out.print("Summer"); case 10, 11, 12 -> System.out.print("Fall"); } }
Calling printSeason(2)
prints the single value Winter
. This time we don't have to worry about break
statements, since only one branch is executed.
switch
expression returns a value, although printSeason()
demonstrates one in which the return type is void
. Since the type is void
, it can't be assigned to a variable. On the exam, you are more likely to see a switch
expression that returns a value, but you should be aware that it is possible.
All of the previous rules around switch
data types and case
values still apply, although we have some new rules. Don't worry if these rules are new to you or you've never seen the yield
keyword before; we'll be discussing them in the following sections.
1 All of the branches of a switch expression that do not throw an exception must return a consistent data type (if the switch expression returns a value).
2 If the switch expression returns a value, then every branch that isn't an expression must yield a value.
3 A default branch is required unless all cases are covered or no value is returned.
We cover the last rule shortly, but notice that our printSeason()
example does not contain a default
branch. Since the switch
expression does not return a value and assign it to a variable, it is entirely optional.
switch
expressions, but since this is a Preview feature, it is not in scope for the exam.
Returning Consistent Data Types
The first rule of using a switch
expression is probably the easiest. You can't return incompatible or random data types. For example, can you see why three of the lines of the following code do not compile?
int measurement = 10; int size = switch(measurement) { case 5 -> 1; case 10 -> (short)2; default -> 5; case 20 -> "3"; // DOES NOT COMPILE case 40 -> 4L; // DOES NOT COMPILE case 50 -> null; // DOES NOT COMPILE };
Notice that the second case
expression