Java 12 предоставляет в экспериментальной форме выражение switch
и новые формы операторов switch
и break
. Существует множество новых синтаксисов и семантик для конструкций, которые могут найти мало пользы, за исключением, конечно, авторов головоломок и вопросов сертификационных экзаменов, для которых это замечательный подарок. Если вам нравятся Java-головоломки и, возможно, вы захотите создать их сами, читайте дальше.
Выражение Выражения Java 12
В Java 12 представлен переключатель выражений — версия switch
которая является выражением, а не оператором. Вот простой пример:
1
2
3
4
5
6
7
8
9
|
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 ; }; } |
Это мило.
Обратите внимание, что эта форма switch
является выражением . У него есть значение, которое в данном случае является выражением в операторе return
. Вы также можете назначить выражение switch
переменной, передать его в качестве аргумента метода и сделать все остальное, что вы можете делать с выражениями в Java.
Эта диаграмма объясняет это кратко:
выражение | утверждение | |
Двусторонняя ветвь | ? : |
if / else |
Многоходовая ветвь | switch |
switch |
Было бы более логично иметь оператор для многопоточного выражения ветвления? Конечно, но … вставь злой смех … так мы получим лучшие загадки!
Преуспевать. Попробуйте. Где вы можете использовать выражение? Конечно, внутри оператора
1
2
3
4
|
switch ( switch (...) { case ... -> ...; case ... -> ... }) { case ...: ...; case ...: ...; } |
Заполните что-нибудь забавное для ...
и спросите, каков будет результат. Также добавьте опцию «это не скомпилируется». (Это ответ. Обратите внимание на пропущенную точку с запятой во второй ветви case
switch
выражений.)
У этого switch
выражений есть замечательная особенность: нет падения . Вам не нужно ставить break
в конце каждой ветви case
.
Это здорово — пропущенный break
является распространенной ошибкой. Но это кажется шагом назад для создателей головоломок.
Не отчаивайся. Я собираюсь принести вам хорошие новости.
Разрывы ценностей
Предположим, вы хотите что-то зарегистрировать в одной из веток.
1
|
case TUESDAY -> { logger.info( "Belgium?" ); 7 } // Not legal Java |
Это синтаксис Scala. В Scala блок — это выражение, значением которого является последнее выражение блока. В этом примере 7. Но у Java нет блочных выражений.
Java 12 (номер версии которого заставляет нас думать о 12 рождественских ночах) приходит с подарком для создателей головоломок: новое заявление о break
. Его цель — вернуть значение из блока в ветке case
:
1
|
case TUESDAY -> { logger.info( "Belgium?" ); break 7 ; } |
Кстати, ->
специально использовался, чтобы напомнить вам о лямбда-выражениях. В лямбда-выражениях у вас есть похожая проблема. Предположим, у вас есть лямбда-выражение, которое дает выражение.
1
|
Runnable task = () -> 42 ; |
И теперь вы хотите добавить запись звонка. Вы делаете что-то очень похожее:
выражение | утверждение | |
лямбда | Runnable r = () -> 42; |
Runnable r = () -> { logger.log(...); return 42; }; |
case ветвь |
case ... -> 42; |
case ... -> { logger.log(...); break 42; } |
Кроме того, читатели с орлиными глазами заметят, что в одном квадранте этой таблицы нет конечных точек с запятой. Больше материала загадки…
Это заявление о break
действительно действует как return
. Он может быть вложен в другой блок, и он выпрыгивает наружу, давая значение.
1
|
case ... -> { if (n % 2 == 0 ) break 42 ; else { logger.log(...); break 21 ; } } |
За исключением, конечно, в циклах и операторах switch
где уже есть другое значение для break
. Например, это незаконно:
1
2
3
4
5
6
|
case ... -> { for ( int i = 0 ; i < a.length; i++) { if (a[i] == x) break i; // Error } break - 1 ; } |
Значение break
точно такое же, как return
, за исключением внутренних циклов и операторов switch
, где это запрещено. Давай, сделай из этого головоломку прямо сейчас. Ты знаешь чего хочешь.
Помеченные перерывы
Еще в 1995 году Java 1.0 представила такие инновации, как классы и интерфейсы, сборка мусора и строки Unicode, в то же время придерживаясь синтаксиса C для структур управления, знакомых многим программистам. За исключением одного изменения.
В Java вы можете использовать помеченный break
чтобы разорвать вложенные циклы и добраться до конца цикла, который имеет соответствующую метку в начале . Как это:
01
02
03
04
05
06
07
08
09
10
11
|
int i = 0 ; int j = 0 ; found: while (i < a.length) { while (j < a[i].length) { if (a[i][j] == x) break found; j++; } i++; } // Execution continues here after break found; |
Вы когда-нибудь использовали эту функцию? Не волнуйся, если нет. Мало людей, вне сертификационных экзаменов.
Что произойдет, если у вас есть цикл внутри case
с break foo;
? Это полностью зависит. Если foo
встречается как метка замкнутого цикла, то у вас есть помеченный break
. Если нет, и foo
является переменной, то у вас есть значение break
. Что делать, если у вас есть оба? Это синтаксическая ошибка.
Давай, сделай из этого загадку. Ты знаешь чего хочешь.
Заявления стрелки
Посмотрите еще раз на синтаксис switch
выражений. Ты можешь сказать
1
|
case MONDAY, FRIDAY, SUNDAY -> |
вместо
1
|
case MONDAY: case FRIDAY: case SUNDAY: |
Это хорошо — альтернатива выглядела бы довольно странно:
1
|
case MONDAY -> case FRIDAY -> case SUNDAY -> // Just kidding |
Так много добра в switch
выражений. Нет провала. Нет необходимости повторять case
. Заявление о switch
становится действительно завистливым.
Итак, Java-дизайнеры решили быть милыми и позволить им принять участие в этом. Теперь вы можете написать:
01
02
03
04
05
06
07
08
09
10
11
12
|
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 ; } |
Непослушные Выражения Выключателя
Теперь настала очередь switch
выражений завидовать. Оператор switch
теперь имеет две формы: непослушный (около 1970 г.) и симпатичный (2018 г.). Что, если switch
выражения хотел быть непослушным, с провалом?
Вот тут и возникает ошибка 2х2 диаграмм:
выражение | утверждение | |||||
Нет прорыва |
|
|
||||
Провалиться |
|
|
Нам действительно нужно заполнить пропущенный квадрант?
Видимо да.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
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 ; }; |
Можете ли вы смешать case ...:
и case ... ->
в одном switch
? К сожалению нет. Это когда-то считалось, но лобби против головоломки озадачило день.
Можете ли вы сделать case MONDAY: case FRIDAY: case SUNDAY:
для первой ветви? Вы можете сделать загадку для этого, но в этот момент ваша аудитория, вероятно, потеряла желание жить.
Pre-Christmas Puzzler For You
Когда я давал представление обо всем этом, я знал, что должен был сделать загадку. Этот переключатель непослушный или хороший? Что оно делает?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
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 ; } }; |
- Есть синтаксическая ошибка
- Существует бесконечный цикл
-
n
установлен в 0 -
n
установлен в 1
Опубликовано на Java Code Geeks с разрешения Cay Hortstmann, партнера нашей программы JCG. См. Оригинальную статью здесь: « Дайте мне передохнуть» или «Как сделать удивительные головоломки с Java 12».
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |