{{announcement.body}}
{{announcement.title}}

Java Switch Expressions For Impatiens

DZone 's Guide to

Java Switch Expressions For Impatiens

This is the super-fast guide of Java 12/13 switch expressions. Learn how to use switch expressions in 5 minutes.

· Java Zone ·
Free Resource

This is the super-fast guide of Java 12/13 switch expressions. Learn how to use switch expressions in 5 minutes.

You may also like: JDK 12: Switch Statements/Expressions in Action

Old-School Switch

Before we have a brief overview of the switch expressions introduced in JDK 12, let's see a typical old-school example wrapped in a method (PlayerTypes is a simple Java enum).

Java
 




x
17


 
1
private static Player createPlayer(PlayerTypes playerType) {
2
  
3
  switch (playerType) {
4
    case TENNIS:
5
      return new TennisPlayer();
6
    case FOOTBALL:
7
      return new FootballPlayer();
8
    case SNOOKER:
9
      return new SnookerPlayer();
10
    case UNKNOWN:
11
      throw new UnknownPlayerException("Player type is unknown");
12
    
13
    default:
14
      throw new IllegalArgumentException(
15
        "Invalid player type: " + playerType);
16
  }
17
}



If we forget about default , then the code will not compile.

The preceding example is acceptable. In the worst-case scenario, we can add a spurious variable (for example, player), some cluttering break statements, and get no complaints if default is missing. So, the following code is an old-school, extremely ugly switch.

Java
 




xxxxxxxxxx
1
24


 
1
private static Player createPlayerSwitch(PlayerTypes playerType) {
2
  
3
  Player player = null;
4
  switch (playerType) {
5
    case TENNIS:
6
      player = new TennisPlayer();
7
      break;
8
    case FOOTBALL:
9
      player = new FootballPlayer();
10
      break;
11
    case SNOOKER:
12
      player = new SnookerPlayer();
13
      break;      
14
    case UNKNOWN:
15
      throw new UnknownPlayerException(
16
        "Player type is unknown");
17
    
18
    default:
19
      throw new IllegalArgumentException(
20
        "Invalid player type: " + playerType);
21
  }
22
  
23
  return player;
24
}



If we forget about default, then there will be no complaints from the compiler side. In this case, a missing default case may result in a null player.

Java 12 Switch Expression

However, since JDK 12, we have been able to rely on the switch expressions. Before JDK 12, switch was a statement, a construct meant to control the flow (for example, like an if statement) without representing the result. On the other hand, an expression is evaluated to a result. Therefore, a switch expression can have a result.

The preceding old-school switch expression can be written in the style of JDK 12 as follows.

Java
 




xxxxxxxxxx
1
14


 
1
private static Player createPlayer(PlayerTypes playerType) {
2
  
3
  return switch (playerType) {
4
    case TENNIS -> new TennisPlayer();
5
    case FOOTBALL -> new FootballPlayer();
6
    case SNOOKER -> new SnookerPlayer(); 
7
    case UNKNOWN -> throw new UnknownPlayerException(
8
      "Player type is unknown");
9
      
10
      // default is not mandatory
11
    default -> throw new IllegalArgumentException(
12
      "Invalid player type: " + playerType);
13
  };
14
}



This time, default  is not mandatory. We can skip it.

The JDK 12 switch is smart enough to signal if switch doesn't cover all possible input values. This is very useful in the case of Java enum values. The JDK 12 switch can detect whether all the enum values are covered, and don't force a useless default if they aren't. For example, if we remove default and add a new entry to PlayerTypes enum (for example, GOLF), then the compiler will signal it via a message, as in the following screenshot (this is from NetBeans).

code snippet

Notice that between the label and execution, we've replaced the colon with an arrow (the lambda-style syntax). The main role of this arrow is to prevent fall-through, which means that only the block of code from its right will be executed. There is no need to use break.

Do not conclude that the arrow turns the switch statement into a switch expression. A switch expression can be used with a colon and break as well, as follows:

Java
 




xxxxxxxxxx
1
14


 
1
private static Player createPlayer(PlayerTypes playerType) {
2
  
3
  return switch (playerType) {
4
    case TENNIS: break new TennisPlayer();
5
    case FOOTBALL: break new FootballPlayer();
6
    case SNOOKER: break new SnookerPlayer();
7
    case UNKNOWN: throw new UnknownPlayerException(
8
      "Player type is unknown");
9
      
10
      // default is not mandatory
11
    default: throw new IllegalArgumentException(
12
      "Invalid player type: " + playerType);
13
  };
14
}



Our example posts switch  over enum , but the JDK 12 switch  can also be used over int , Integer , short , Short , byte , Byte , char , Character , and String .

Notice that JDK 12 brings the switch  expressions as a preview feature. This means that it is prone to changes in the next few releases, and it needs to be unlocked via the --enablepreview command-line  option at compiling and runtime.

The complete example is available on GitHub.

Multiple Case Labels

Before JDK 12, a switch statement allowed a single label per case. Starting with the switch expressions, a case can have multiple labels separated by a comma. Check out the following method that exemplifies multiple case labels:

Java
 




xxxxxxxxxx
1


 
1
private static SportType fetchSportTypeByPlayerType(PlayerTypes playerType) {
2
  
3
  return switch (playerType) {
4
    case TENNIS, GOLF, SNOOKER -> new Individual();
5
    case FOOTBALL, VOLLEY -> new Team();
6
  };
7
}



If we pass to this method TENNIS, GOLF, or SNOOKER, it will return an instance of the Individual class. If we pass FOOTBALL or VOLLEY, it will return an instance of the Team class.

The complete example is available on GitHub.

Statement Blocks

A label's arrow can point to a single statement (as in the examples from the previous two examples) or a curly-braced block. This is pretty similar to the lambda blocks. Check out the following solution:

Java
 




xxxxxxxxxx
1
20


 
1
private static Player createPlayer(PlayerTypes playerType) {
2
  
3
  return switch (playerType) {
4
    case TENNIS -> {
5
      System.out.println("Creating a TennisPlayer ...");
6
      break new TennisPlayer();
7
    }
8
    case FOOTBALL -> {
9
      System.out.println("Creating a FootballPlayer ...");
10
      break new FootballPlayer();
11
    }
12
    case SNOOKER -> {
13
      System.out.println("Creating a SnookerPlayer ...");
14
      break new SnookerPlayer();
15
    }
16
       
17
    default -> throw new IllegalArgumentException(
18
      "Invalid player type: " + playerType);
19
  };
20
}



Notice that we exit from a curly-braced block via break, not return. In other words, while we can return from inside a switch statement, we can't return from within an expression.

The complete example is available on GitHub.

Java 13 Switch Expressions

However, since JDK 13, the break with a value statement is dropped in favor of a yield statement. The rest remains the same. So, using yield we obtain:

Java
 




xxxxxxxxxx
1
14


 
1
private static Player createPlayer(PlayerTypes playerType) {
2
  
3
  return switch (playerType) {
4
    case TENNIS: yield new TennisPlayer();
5
    case FOOTBALL: yield new FootballPlayer();
6
    case SNOOKER: yield new SnookerPlayer();
7
    case UNKNOWN: throw new UnknownPlayerException(
8
      "Player type is unknown");
9
      
10
      // default is not mandatory
11
    default: throw new IllegalArgumentException(
12
      "Invalid player type: " + playerType);
13
  };
14
}



The complete example is available on GitHub.

We also obtain:

Java
 




xxxxxxxxxx
1
20


 
1
private static Player createPlayer(PlayerTypes playerType) {
2
  
3
  return switch (playerType) {
4
    case TENNIS -> {
5
      System.out.println("Creating a TennisPlayer ...");
6
      yield new TennisPlayer();
7
    }
8
    case FOOTBALL -> {
9
      System.out.println("Creating a FootballPlayer ...");
10
      yield new FootballPlayer();
11
    }
12
    case SNOOKER -> {
13
      System.out.println("Creating a SnookerPlayer ...");
14
      yield new SnookerPlayer();
15
    }
16
       
17
    default -> throw new IllegalArgumentException(
18
      "Invalid player type: " + playerType);
19
  };
20
}


In a nutshell, the arrow does not signify an expression instead of a statement. The arrow-form prevents fall-through.

Labels with a colon merely mark an entry point into an execution. From there it continues, even when it passes another label. In  switch , we know this as fall-through. In other words, a  case  label determines where the control flow jumps to, but it needs a  break ,  yield  or  return  to quit flowing through the  switch .

On the other hand, the arrow-form signifies that only the block to its right will be executed. That’s right, no fall-through!

Done! The complete example is available on GitHub.

If you enjoyed this article, then you'll love my book, Java Coding Problems, that entirely dedicated to JDK 8 to JDK 13 features.

Happy coding!


Further Reading

Java 12: Mapping With Switch Expressions

Java Switch Statement

Playing With JDK 12's Switch Expressions

Topics:
java ,switch expressions ,java switch ,jdk 12 ,jdk 13

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}