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, являются их собственными. |