Совсем недавно Oracle приняла новую стратегию выпуска новой языковой версии каждые шесть месяцев. Стратегия предполагает, что только каждая третья версия будет иметь долгосрочную поддержку или LTS. Краткие заметки об этом:
- Текущая версия с LTS — Java 8;
- Предполагается, что Java 9 будет иметь поддержку только до марта 2018 года, поэтому она уже закончена;
- Java 10 поддерживается до сентября 2018 года;
- Предполагается, что следующей версией LTS будет Java 11, которая должна быть выпущена в сентябре 2018 года и будет поддерживаться по крайней мере до сентября 2023 года.
Подробнее об этом здесь в Oracle Java SE.
Наша компания до сих пор не приняла Java 9, но теперь кажется, что ее можно полностью пропустить и перейти к следующему LTS. Есть много других проблем, кроме самой Java, например, версии Spring Boot Java и т. Д., Поэтому мы, вероятно, будем действовать осторожно. Тем не менее, ввиду неизбежных изменений, я решил посмотреть, что будет в Java 10. И похоже, что главное в этой версии — это вывод локальных типов .
Мы все знаем этот синтаксис Java:
|
1
2
3
|
List<User> list = new ArrayList<User>();// or since Java 7List<User> list = new ArrayList<>(); |
По сути, вывод локального типа — это возможность заменить его следующим:
|
1
2
|
// left side type is inferred from the right side and will be ArrayListvar userList = new ArrayList(); |
Это означает, что в коде немного меньше стандартного шаблона, но вам нужно больше внимания уделять именам переменных и методов, потому что ключевое слово var самоочевидно.
Локальный вывод типов уже давно существует во многих языках программирования, таких как Scala, C #, Go и, конечно, Kotlin. В этом отношении Java отставала, и теперь решила это исправить. Тем не менее, было некоторое противоречие в отношении конкретной реализации этого. Например, была возможность:
- иметь val для локальных констант и var для переменных, как в Kotlin или Scala;
- наличие const или только final для локальных констант и var для переменных, поскольку const и final уже зарезервированы в Java;
- наличие окончательного var для констант и var для переменных;
- используя let , def или : = ;
- и больше об этом здесь.
Наконец, было решено сохранить синтаксис ближе к тому, что уже есть, и разрешить var для локальных переменных и final var для локальных констант, поэтому приведенный выше пример будет работать в Java 10. Однако замена не всегда проста. Например:
|
1
2
3
4
5
6
7
8
|
// example 1 - list is a List<User> typeList<User> list = new ArrayList<>();// example 2 - userList is an ArrayList<Object> type, so you lose type informationvar userList = new ArrayList<>();// example 3 - userListFixed is an ArrayList<User> type, so you keep type informationvar userListFixed = new ArrayList<User>(); |
Здесь, во втором примере, с прямой заменой левой части компилятор не может определить тип списка, поэтому он по умолчанию будет Object. Который сбивает вас с толку, когда вы пытаетесь обработать элементы из списка.
Одним из примеров, где вывод локального типа полезен, являются преобразования данных. Например, вы хотите изменить объекты одного типа на другой, имеющие разные атрибуты, и использовать для этого анонимный класс. В Java 8 вы могли делать это только внутри области потока, поэтому, например, новые свойства будут доступны вам в потоке, но не снаружи.
|
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
26
27
28
|
List<User> users = Arrays.asList( new User("Elisabeth", "Bennett", 20), new User("Jane", "Bennett", 22), new User("Mary", "Bennett", 18), new User("Kitty", "Bennett", 17), new User("Lydia", "Bennett", 15) ); users.stream() .map(u -> new Object() { String fullName = u.firstName + " " + u.lastName; boolean canDrink = u.age >= 18; }) .forEach(u -> { if (u.canDrink) { System.out.println("+ " + u.fullName + " is of age and can drink"); } else { System.out.println("- " + u.fullName + " is not of age and cannot drink"); } }); /* Output will be * + Elisabeth Bennett is of age and can drink * + Jane Bennett is of age and can drink * + Mary Bennett is of age and can drink * - Kitty Bennett is not of age and cannot drink * - Lydia Bennett is not of age and cannot drink */ |
В Java 10 вы можете использовать преобразованный список нового объекта вне конвейера потока.
|
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<User> users = Arrays.asList( new User("Elisabeth", "Bennett", 20), new User("Jane", "Bennett", 22), new User("Mary", "Bennett", 18), new User("Kitty", "Bennett", 17), new User("Lydia", "Bennett", 15) ); final var objects = users.stream() .map(u -> new Object() { String fullName = u.firstName + " " + u.lastName; boolean canDrink = u.age >= 18; }) .collect(Collectors.toUnmodifiableList()); // do something with the users... System.out.println(); for (var o : objects) { if (o.canDrink) { System.out.println("+ " + o.fullName + " is of age and can drink"); } else { System.out.println("- " + o.fullName + " is not of age and cannot drink"); } } |
Итак, после закрытия потока свойства сопоставленного объекта все еще доступны. Однако, поскольку это локальный тип, вы не сможете использовать их вне локальной области текущего метода. Ключевое слово var не будет работать в объявлении параметров метода, поэтому вы не можете передать переменную в другой метод. Таким образом, наличие var не означает, что Java волшебным образом становится динамически типизированной. Он по-прежнему типизирован статически, только с добавленным кусочком синтаксического сахара, и только в тех местах, где компилятор может определить тип.
Для меня это показывает, что Java стремится двигаться вперед, но ей очень мешают пытаться сохранить исторические корни, делая обратную совместимость, а не инновации своим главным приоритетом.
| Опубликовано на Java Code Geeks с разрешения Марины Чернявской, партнера нашей программы JCG . См. Оригинальную статью здесь: Локальный вывод типа в Java 10, или Если он крякает, как утка |