Arrow form — no fallthrough, and it produces a value:
varlabel=switch(day){case1,7->"weekend";case2,3,4,5,6->"weekday";default->thrownewIllegalArgumentException("bad day: "+day);};vartext=switch(grade){case1->"excellent";default->{vars="grade "+grade;yields.toUpperCase();// yield inside a block}};
Pattern matching
Stringdescribe(Objecto){returnswitch(o){caseIntegeriwheni>100->"big number: "+i;caseIntegeri->"number: "+i;caseStrings->"text of %d chars".formatted(s.length());caseint[]a->"array of "+a.length;casenull->"nothing";default->"unknown";};}
when adds a guard. Without case null, a null value throws.
for(varname:names){…}// for-each: the defaultfor(vari=0;i<5;i++){…}// when you need the indexfor(vari=10;i>0;i-=2){…}while(rest>1){rest/=2;}do{answer=IO.readln("again? ");}// runs at least oncewhile(!answer.equals("n"));
break and continue
for(varn:numbers){if(n%2!=0)continue;// skipif(n>15)break;// leave the loopIO.println(n);}
Labels exist for nested loops, but extracting a method and return is usually cleaner:
outer:for(…){for(…){if(…)breakouter;}}
Putting it together
voidmain(){varsecret=newjava.util.Random().nextInt(1,101);vartries=0;while(true){varinput=IO.readln("Guess 1-100: ");intguess;try{guess=Integer.parseInt(input.strip());}catch(NumberFormatExceptione){IO.println("Not a number.");continue;}tries++;switch(Integer.compare(guess,secret)){case-1->IO.println("too low");case1->IO.println("too high");default->{IO.println("Got it in %d tries!".formatted(tries));return;}}}}
★ Exercises
Print a multiplication table from 1 to 10, aligned with "%4d".
FizzBuzz for 1–100 — once with if/else, once with a switch expression.
Print all primes up to n.
Write String classify(Object o) handling Integer, Double, String, List and null.
Add a Triangle to the shapes above. What does the compiler say about your old switch?
Change the guessing game to stop after 7 wrong guesses.