Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

The JVM Advent Calendar: How to Make Awesome Puzzlers With Java 12

DZone's Guide to

The JVM Advent Calendar: How to Make Awesome Puzzlers With Java 12

This holiday season, learn how to make awesome puzzlers with Java 12.

· Java Zone ·
Free Resource

FlexNet Code Aware, a free scan tool for developers. Scan Java, NuGet, and NPM packages for open source security and open source license compliance issues.

Java 12 provides, in experimental form, a switch expression and new forms of the switch and break statements. There is a profusion of new syntax and semantics for constructs that may find little use-except, of course, for authors of puzzlers and certification exam questions for whom this is a wonderful gift. If you enjoy Java puzzlers and would perhaps like to create some yourself, read on.

The Java 12 Expression Switch

Java 12 introduces an expression switch — a version of switch that is an expression, not a statement. Here is a simple example:

enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY };
public static int numLetters(Day day) {
   return switch (day) {
      case MONDAY, FRIDAY, SUNDAY -> 6;
      case TUESDAY -> 7;
      case THURSDAY, SATURDAY -> 8;
      default -> 9;
   };
}


That's nice.

Note that this form of switch is an expression. It has a value that, in this case, is the expression in the return statement. You could also assign the switch expression to a variable, pass it as a method argument, and do all the other things that you can do with expressions in Java.

This diagram explains it concisely:

Image title

Would it have been more consistent to have an operator for a multi-way branch expression? Sure, but ... insert evil laugh here ... this way, we get to make better puzzlers!

Go ahead. Give it a try. Where can you use an expression? Inside a switch statement, of course.

switch (switch (...) { case ... -> ...; case ... -> ... }) {
   case ...: ...; 
   case ...: ...; 
}


Fill in something amusing for the ... and ask what the outcome is. Also toss in an option for "it won't compile." (That's the answer. Note the missing semicolon in the second case branch of the expression switch.)

This expression switch has a remarkable feature: no fall-through. You don't have to put a break at the end of each case branch.

That's great-a missing break is a common error. But it seems a step backward for puzzler makers.

Don't despair. I am about to bring you good tidings.

Value Breaks

Suppose you want to log something in one of the branches.

case TUESDAY -> { logger.info("Belgium?"); 7 } // Not legal Java


That's Scala syntax. In Scala, a block is an expression whose value is the last expression of the block. In this example, 7. But Java doesn't have block expressions.

Java 12 (whose version number makes us think of the 12 nights of Christmas), comes bearing a gift for puzzle makers: a new break statement. Its purpose is to return a value out of a block in a case branch:

case TUESDAY -> { logger.info("Belgium?");break 7; }


By the way, the -> was purposefully used to remind you of lambda expressions. In lambda expressions, you have a similar problem. Suppose you have a lambda expression that yields an expression.

Runnable task = () -> 42;


And now, you want to add a logging call. You do something quite similar:

Image title

As an aside-eagle-eyed reader will notice, there are no terminal semicolons in one quadrant of this table. More puzzler material.

This break statement really acts like return. It can be nested inside another block, and it jumps outside, yielding the value.

case ... -> { if (n % 2 == 0) break 42; else { logger.log(...); break 21; } }


Except, of course, in loops and switch statements, where there is already a different meaning for break. For example, this is illegal:

case ... -> {
   for (int i = 0; i < a.length; i++) {
      if (a[i] == x) break i; // Error
   }
   break -1;
}


Value break is exactly like return, except inside loops and switch statements, where it is forbidden. Go ahead — make a puzzler out of that right now. You know you want to.

Labeled Breaks

Way back in 1995, Java 1.0 introduced innovations, such as classes and interfaces, garbage collection, and Unicode strings, while sticking to the C syntax for control structures that was familiar to so many programmers — except for one teensy change.

In Java, you can use a labeled break to break out of nested loops and get to the end of the loop that has the matching label at the beginning. Like this:

int i = 0;
int j = 0;
found:
while (i < a.length) {
   while (j < a[i].length) {
      if (a[i][j] == x) breakfound; j++; } i++; } // Execution continues here after break found;


Did you ever use this feature? Don't worry, if not. Few people have outside certification exams.

What happens if you have a loop inside a case with a break foo;? It entirely depends. If foo occurs as a label of an enclosing loop, then you have a labeled break. If not, and foo is a variable, then you have a value break. What if you have both? That's a syntax error.

Go ahead, make a puzzler out of that. You know you want to.

Arrow Switch Statements

Have another look at the expression switch syntax. You can say:

case MONDAY, FRIDAY, SUNDAY ->


Instead of:

case MONDAY: case FRIDAY: case SUNDAY:


That's a good — the alternative would have looked pretty weird:

case MONDAY -> case FRIDAY -> case SUNDAY -> // Just kidding


So much goodness in the expression switch. No fallthrough. No need to repeat case. The switch statement is getting really envious.

So, the Java designers decided to be nice and allow it to partake in that goodness. You can now write:

switch (day) {
   case MONDAY, FRIDAY, SUNDAY -> // No repeating of case
      numLetters = 6; // No fallthrough after ->
   case TUESDAY -> { 
      logger.info("Tuesday"); 
      numLetters = 7; 
   } 
   case THURSDAY, SATURDAY -> 
      numLetters = 8; 
   default -> 
      numLetters = 9; 
}


Naughty Switch Expressions

Now it is the expression switch's turn to get envious. The switch statement now has two forms: naughty (circa 1970) and nice (2018). What if the expression switch wanted to be naughty, with fallthrough?

This is where the fallacy of 2 x 2 diagrams comes in:

Image title

Do we really need to fill in the missing quadrant?

Apparently, yes.

int numLetters = switch(day) {
   case MONDAY, FRIDAY, SUNDAY:
      break 6;
   case TUESDAY:
      logger.info("Tuesday");
      break 7;
   case THURSDAY:
      logger.info("Thursday"); //Fallthrough case SATURDAY: break 8; default: break 9; };


Can you mix case ...: and case ... -> in the same switch? Sadly, no. This was once considered, but the anti-puzzler lobby carried the day.

Can you do case MONDAY: case FRIDAY: case SUNDAY: for the first branch? You can make a puzzler for that, but at that point, your audience probably lost the will to live.

A Pre-Christmas Puzzler For You

When I gave a presentation about all this, I knew I had to make a puzzler. Is this switch naughty or nice? What does it do?

      int n = 0;
      n = switch (n) {
         case 0:
            n++;
         default: {
            O:
            while (n > 0) {
               if (n == 1) break O;
               n--;
            }
            if (n > 0) 
               break n;
            else
               break 0;
         }
      };


1. There is a syntax error.

2. There is an infinite loop.

3. n is set to 0

4. n is set to 1

 Scan Java, NuGet, and NPM packages for open source security and license compliance issues. 

Topics:
java ,switch expressions ,switch ,lambdas ,lambda expressions ,java 12 ,jvm

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}