В этой статье мы рассмотрим новую функцию Java 12 «Выражения переключателя» и то, как ее можно использовать в сочетании с
Операция Stream::map
и некоторые другие операции Stream. Узнайте, как вы можете улучшить свой код с помощью потоков и выражений переключателей.
Переключатель выражений
Java 12 поставляется с поддержкой «предварительного просмотра» «Switch Expressions». Выражение Switch позволяет операторам switch возвращать значения напрямую, как показано ниже:
1
2
3
4
5
6
7
|
public String newSwitch( int day) { return switch (day) { case 2 , 3 , 4 , 5 , 6 -> "weekday" ; case 7 , 1 -> "weekend" ; default -> "invalid" ; } + " category" ; } |
Вызов этого метода с 1
вернет «категорию выходного дня».
Это здорово и делает наш код короче и лаконичнее. Нам не нужно беспокоиться о возможных проблемах, блоках, изменяемых временных переменных или пропущенных случаях / дефолтах, которые могут иметь место для переключателя good ole. Просто посмотрите на этот соответствующий старый пример коммутатора, и вы поймете, что я имею в виду:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public String oldSwitch( int day) { final String attr; switch (day) { case 2 , 3 , 4 , 5 , 6 : { attr = "weekday" ; break ; } case 7 , 1 : { attr = "weekend" ; break ; } default : { attr = "invalid" ; } } return attr + " category" ; } |
Переключатель выражений является функцией предварительного просмотра
Чтобы заставить Switch Expression работать под Java 12, мы должны передать
“--enable-preview”
как аргумент командной строки, когда мы компилируем и запускаем наше приложение. Это оказалось немного сложнее, но, надеюсь, станет легче с выпуском новых версий IDE и / или / если Java включит эту функцию в качестве полностью поддерживаемой функции. Пользователи IntelliJ должны использовать версию 2019.1 или новее.
Переключение выражений в Stream :: map
Выражения-переключатели очень просты в использовании в операторах Stream::map
, особенно по сравнению со старым синтаксисом-переключателем. В приведенных ниже примерах я использовал ORM Speedment Stream и примерную базу данных Sakila . База данных Sakila — это все о фильмах, актерах и так далее.
Вот поток, который декодирует идентификатор языка фильма ( short
) в полное имя языка ( String
), используя map()
в сочетании с выражением Switch:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public static void main(String... argv) { try (Speedment app = new SakilaApplicationBuilder() .withPassword( "enter-your-db-password-here" ) .build()) { FilmManager films = app.getOrThrow(FilmManager. class ); List<String> languages = films.stream() .map(f -> "the " + switch (f.getLanguageId()) { case 1 -> "English" ; case 2 -> "French" ; case 3 -> "German" ; default -> "Unknown" ; } + " language" ) .collect(toList()); System.out.println(languages); } } |
Это создаст поток из всех 1000 фильмов в базе данных, а затем сопоставит каждый фильм с именем соответствующего языка и соберет все эти имена в список. Выполнение этого примера приведет к следующему выводу (сокращенно для краткости):
[английский язык, английский язык,…]
Если бы мы использовали старый синтаксис переключателя, мы бы получили что-то вроде этого:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
... List<String> languages = films.stream() .map(f -> { final String language; switch (f.getLanguageId()) { case 1 : { language = "English" ; break ; } case 2 : { language = "French" ; break ; } case 3 : { language = "German" ; break ; } default : { language = "Unknown" ; } } return "the " + language + " language" ; }) .collect(toList()); ... |
Или, может быть, что-то вроде этого:
01
02
03
04
05
06
07
08
09
10
11
12
|
... List<String> languages = films.stream() .map(f -> { switch (f.getLanguageId()) { case 1 : return "the English language" ; case 2 : return "the French language" ; case 3 : return "the German language" ; default : return "the Unknown language" ; } }) .collect(toList()); ... |
Последний пример короче, но дублирует логику.
Переключение выражений в Stream :: mapToInt
В этом примере мы вычислим сводную статистику о баллах, которые мы присваиваем на основе рейтинга фильма. Чем более ограничены, тем выше оценка в соответствии с нашей собственной изобретенной шкалой:
01
02
03
04
05
06
07
08
09
10
11
12
|
IntSummaryStatistics statistics = films.stream() .mapToInt(f -> switch (f.getRating().orElse( "Unrated" )) { case "G" , "PG" -> 0 ; case "PG-13" -> 1 ; case "R" -> 2 ; case "NC-17" -> 5 ; case "Unrated" -> 10 ; default -> 0 ; }) .summaryStatistics(); System.out.println(statistics); |
Это даст следующий результат:
1
|
IntSummaryStatistics{count= 1000 , sum= 1663 , min= 0 , average= 1.663000 , max= 5 } |
В этом случае разница между выражениями коммутатора и старым коммутатором не так уж велика. Используя старый ключ, мы могли бы написать:
01
02
03
04
05
06
07
08
09
10
11
12
|
IntSummaryStatistics statistics = films.stream() .mapToInt(f -> { switch (f.getRating().orElse( "Unrated" )) { case "G" : case "PG" : return 0 ; case "PG-13" : return 1 ; case "R" : return 2 ; case "NC-17" : return 5 ; case "Unrated" : return 10 ; default : return 0 ; } }) .summaryStatistics(); |
Переключение выражений в Stream :: collect
В последнем примере показано использование выражения switch в группировке по Collector. В этом случае мы бы хотели посчитать, сколько фильмов может посмотреть человек определенного минимального возраста. Здесь мы используем карту с минимальным возрастом в качестве ключей и подсчитываем фильмы в качестве значений.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
Map<Integer, Long> ageMap = films.stream() .collect( groupingBy( f -> switch (f.getRating().orElse( "Unrated" )) { case "G" , "PG" -> 0 ; case "PG-13" -> 13 ; case "R" -> 17 ; case "NC-17" -> 18 ; case "Unrated" -> 21 ; default -> 0 ; }, TreeMap:: new , Collectors.counting() ) ); System.out.println(ageMap); |
Это даст следующий результат:
1
|
{ 0 = 372 , 13 = 223 , 17 = 195 , 18 = 210 } |
Предоставляя (необязательно) поставщика TreeMap::new
Map TreeMap::new
, мы получаем возраст в отсортированном порядке. Почему PG-13 можно увидеть с 13 лет, а NC-17 — с 17, а с 18 лет — загадочно, но выходит за рамки этой статьи.
Резюме
Я с нетерпением жду, чтобы функция Switch Expressions была официально включена в Java. Выражения-переключатели иногда могут заменять лямбда-выражения и ссылки на методы для многих типов потоковых операций.
См. Оригинальную статью здесь: Java 12: Отображение с помощью выражений коммутатора. Мнения, высказанные участниками Java Code Geeks, являются их собственными. |