Скачать книгу

returns a short, but that can be implicitly cast to an int. In this manner, the values have to be consistent with size, but they do not all have to be the same data type. The last three case expressions do not compile because each returns a type that cannot be assigned to the int variable.

      Applying a case Block

      A switch expression supports both an expression and a block in the case and default branches. Like a regular block, a case block is one that is surrounded by braces ({}). It also includes a yield statement if the switch expression returns a value. For example, the following uses a mix of case expressions and blocks:

      The yield keyword is equivalent to a return statement within a switch expression and is used to avoid ambiguity about whether you meant to exit the block or method around the switch expression.

      Referring to our second rule for switch expressions, yield statements are not optional if the switch statement returns a value. Can you see why the following lines do not compile?

      10: int fish = 5; 11: int length = 12; 12: var name = switch(fish) { 13: case 1 -> "Goldfish"; 14: case 2 -> {} // DOES NOT COMPILE 15: case 3 -> { 16: if(length > 10) yield "Blobfish"; 17: } // DOES NOT COMPILE 18: default -> "Swordfish"; 19: };

      Line 14 does not compile because it does not return a value using yield. Line 17 also does not compile. While the code returns a value for length greater than 10, it does not return a value if length is less than or equal to 10. It does not matter that length is set to be 12; all branches must yield a value within the case block.

      Watch Semicolons in switch Expressions

      Unlike a regular switch statement, a switch expression can be used with the assignment operator and requires a semicolon when doing so. Furthermore, semicolons are required for case expressions but cannot be used with case blocks.

      A bit confusing, right? It's just one of those things you have to train yourself to spot on the exam.

      Covering All Possible Values

      The last rule about switch expressions is probably the one the exam is most likely to try to trick you on: a switch expression that returns a value must handle all possible input values. And as you saw earlier, when it does not return a value, it is optional.

      Let's try this out. Given the following code, what is the value of type if canis is 5?

      String type = switch(canis) { // DOES NOT COMPILE case 1 -> "dog"; case 2 -> "wolf"; case 3 -> "coyote"; };

      There's no case branch to cover 5 (or 4, -1, 0, etc.), so should the switch expression return null, the empty string, undefined, or some other value? When adding switch expressions to the Java language, the authors decided this behavior would be unsupported. Every switch expression must handle all possible values of the switch variable. As a developer, there are two ways to address this:

       Add a default branch.

       If the switch expression takes an enum value, add a case branch for every possible enum value.

      In practice, the first solution is the one most often used. The second solution applies only to switch expressions that take an enum. You can try writing case statements for all possible int values, but we promise it doesn't work! Even smaller types like byte are not permitted by the compiler, despite there being only 256 possible values.

      For enums, the second solution works well when the number of enum values is relatively small. For example, consider the following enum definition and method:

      enum Season {WINTER, SPRING, SUMMER, FALL} String getWeather(Season value) { return switch(value) { case WINTER -> "Cold"; case SPRING -> "Rainy"; case SUMMER -> "Hot"; case FALL -> "Warm"; }; }

      Tip Icon What happens if you use an enum with three values and later someone adds a fourth value? Any switch expressions that use the enum without a default branch will suddenly fail to compile. If this was done frequently, you might have a lot of code to fix! For this reason, consider including a default branch in every switch expression, even those that involve enum values.

      A common practice when writing software is doing the same task some number of times. You could use the decision structures we have presented so far to accomplish this, but that's going to be a pretty long chain of if or else statements, especially if you have to execute the same thing 100 times or more.

      Enter loops! A loop is a repetitive control structure that can execute a statement of code multiple times in succession. By using variables that can be assigned new values, each repetition of the statement may be different. The following loop executes exactly 10 times:

      int counter = 0; while (counter < 10) { double price = counter * 10; System.out.println(price); counter++; }

      If you don't follow this code, don't panic—we cover it shortly. In this section, we're going to discuss the while loop and its two forms. In the next section, we move on to for loops, which have their roots in while loops.

      The while Statement

      As shown in Figure 3.5, a while loop is similar to an if statement in that it is composed of a boolean expression and a statement, or a block of statements. During execution, the boolean expression is evaluated before each iteration of the loop and exits if the evaluation returns false.

      Let's see how a loop can be used to model a mouse eating

Скачать книгу