Java 10 – самый быстрый релиз за 23-летнюю историю языка Java. Java часто критиковали за медленное развитие, но Java 10 разрушила этот стереотип. Этот релиз внес множество инновационных изменений, сфера и влияние которых могут быть неочевидными, но далеко идущими. В этой статье мы обсудим различные функции, добавленные в релиз Java 10. Но перед этим давайте рассмотрим некоторые изменения, внесенные в модель релизов Java.
Модель с долгосрочной поддержкой
С 2017 года Oracle и Java-сообщество объявили о переходе к новому циклу релизов каждые 6 месяцев для Java. Была введена модель долгосрочной поддержки (LTS) для продуктов Oracle Java SE. Что это означает? Версии с долгосрочной поддержкой продуктов будут получать первоклассную и устойчивую поддержку от Oracle, и они будут выпускаться каждые 3 года. Каждый релиз Java моделируется по одной или двум основным функциям, которые определяют выпуск. Любые препятствия задерживают выпуск и могут привести к его задержке. Проект Jigsaw был важной функцией в Java 9, он несколько раз откладывал даты выпуска, и выпуск был задержан более чем на 1,5 года. Релизы с интервалом в 6 месяцев будут следовать поезду релизов. У поезда релизов будет расписание каждые 6 месяцев. Функции, прошедшие отбор, попадают в поезд; в противном случае они ждут следующего запланированного поезда.
Oracle JDK против Open JDK
Для большей удобности разработчиков сейчас сообщество Oracle и Java продвигает бинарные файлы OpenJDK в качестве основного JDK на будущее. Это большое облегчение по сравнению с ранними днями, когда бинарные файлы JDK были собственностью и лицензировались Oracle, что сопровождалось различными ограничениями в отношении их распространения. Однако Oracle будет продолжать производить свой JDK, но только для долгосрочных версий с поддержкой. Это шаг в сторону большей дружественности к облаку и контейнерам, поскольку бинарные файлы open JDK могут распространяться в составе контейнера. Что это означает? Бинарные файлы Open JDK будут выпускаться каждые 6 месяцев, в то время как бинарные файлы Oracle JDK будут выпускаться каждые 3 года (версии LTS). Какие бинарные файлы JDK будут приняты? Крупным организациям требуется время для перехода между версиями; они удерживаются на версии, пока могут. Принятие Java 6 в индустрии было больше, чем Java 7, а затем индустрия постепенно переходит на Java 8. По моему мнению, наибольшей популярностью будут пользоваться версии LTS среди предприятий. Однако пока неизвестно, будет ли это версия LTS Oracle JDK или Open JDK, частично потому, что на пространстве облака происходит многое. Java 9 и 10 – это версии без LTS. Java 11, которая должна выйти в сентябре 2018 года, будет версией LTS.
Функции Java 10
Давайте заглянем в особенности, доступные в Java 10.
С принятием цикла выпусков на основе времени Oracle изменила схему версионирования платформы Java SE и JDK, а также связанную информацию о версиях, для текущих и будущих моделей релизов на основе времени. Новый шаблон номера версии: $FEATURE.$INTERIM.$UPDATE.$PATCH
$FEATURE: счетчик будет увеличиваться каждые 6 месяцев и будет основан на версиях выпусков функций, например: JDK 10, JDK 11. $INTERIM: счетчик будет увеличиваться для не-функциональных выпусков, содержащих совместимые исправления ошибок и улучшения, но без несовместимых изменений. Обычно это будет равно нулю, так как за шестимесячный период не будет ни одного промежуточного выпуска. Это оставлено для будущего изменения в модели выпуска. $UPDATE: счетчик будет увеличиваться для совместимых обновлений, исправляющих проблемы безопасности, регрессии и ошибки в новых функциях. Это обновляется через месяц после выпуска функции и затем каждые 3 месяца. Версия от апреля 2018 года – JDK 10.0.1, версия от июля – JDK 10.0.2 и так далее $PATCH: счетчик будет увеличиваться для экстренного выпуска, исправляющего критическую проблему. Были добавлены новые API для получения этих значений счетчика программно. Давайте посмотрим;
Version version = Runtime.version();
version.feature();
version.interim();
version.update();
version.patch();
Теперь давайте посмотрим на Java-запускатель, который возвращает информацию о версии:
$ java -version
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)
Формат номера версии – “10”, так как нет другого счетчика, кроме нуля. Дата выпуска добавлена. 18.3 можно прочитать как Год 2018 и 3-й Месяц, сборка 10+46 – это 46-я сборка для версии 10. Для гипотетической сборки 93 JDK 10.0.1 сборка будет 10.0.1+939. ### Локальное встраивание типа переменной (JEP 286)
Локальный вывод типа переменной – самая крупная новинка в Java 10 для разработчиков. Он добавляет вывод типа к объявлениям локальных переменных с инициализаторами. Локальный вывод типа может использоваться только в следующих сценариях:
- Ограничен только локальной переменной с инициализатором
- Индексы усовершенствованного цикла for или индексы
- Локально объявлено в цикле for
Давайте рассмотрим его использование:
var numbers = List.of(1, 2, 3, 4, 5); // inferred value ArrayList
// Индекс усовершенствованного цикла for
for (var number : numbers) {
System.out.println(number);
}
// Локальная переменная, объявленная в цикле
for (var i = 0; i < numbers.size(); i++) {
System.out.println(numbers.get(i));
}
Вы можете узнать больше об этом в нашем эксклюзивном сообщении о инференции типа локальной переменной в Java 10.
Эта функция позволяет использовать компилятор JIT на основе Java, Graal, в качестве экспериментального компилятора JIT на платформе Linux/x64. Это далеко не самое передовое включение в список функций Java 10. Graal был введен в Java 9. Это альтернатива компилятору JIT, с которым мы привыкли работать. Это плагин для JVM, что означает, что компилятор JIT не привязан к JVM, и его можно динамически подключать и заменять другим плагином, который совместим с JVMCI (интерфейс компилятора JVM на уровне Java). Кроме того, он внедряет компиляцию Ahead of Time (AOT) в мир Java. Также поддерживается интерпретация языков polyglot. “Компилятор JIT на основе Java, написанный на Java, для преобразования байткода Java в машинный код.” Это запутано? Если JVM написана на Java, то вам не нужна JVM для запуска JVM? JVM может быть скомпилирована AOT, а затем компилятор JIT может использоваться внутри JVM для улучшения производительности путем оптимизации кода в реальном времени. Graal – это полная переработка компилятора JIT на Java с нуля. Предыдущий компилятор JIT был написан на c++. Это считается одним из последних этапов эволюции любого языка программирования. Вы можете переключиться на Graal с помощью следующих параметров JVM:
-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
Больше информации о Graal можно узнать из презентации Криса Ситона.16. ### Общее использование данных класса приложения (JEP 310)
Эта функция помогает улучшить отпечаток запуска, расширяя существующую функцию Class-Data Sharing (“CDS”), чтобы позволить размещать классы приложения в общем архиве. JVM при запуске выполняет некоторые предварительные шаги, одним из которых является загрузка классов в память. Если есть несколько jar-файлов с несколькими классами, то задержка при первом запросе явно заметна. Это становится проблемой с архитектурой без сервера, где время загрузки критично. Чтобы сократить время запуска приложения, можно использовать Class-data sharing для приложения. Идея состоит в том, чтобы уменьшить отпечаток, путем обмена общими метаданными класса между различными процессами Java. Это можно достичь следующими 3 шагами: Определение классов для архивирования: Используйте запуск Java для создания списка файлов для архивирования, это можно сделать с помощью следующих параметров:
$java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst -cp hello.jar HelloWorld
Создание архива AppCDS: Используйте запуск Java для создания архива списка файлов, которые будут использоваться для приложения CDS, это можно сделать с помощью следующих параметров:
$java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst -XX:SharedArchiveFile=hello.jsa -cp hello.jar
Использование архива AppCDS: Используйте запуск Java с следующими параметрами, чтобы использовать Class-data sharing для приложения.
$java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa -cp hello.jar HelloWorld
G1 сборщик мусора стал более предпочтительным в JDK 9. Сборщик мусора G1 избегает полного сбора мусора, но когда параллельные потоки для сборки не могут быстро восстановить память, пользовательский опыт страдает. Это изменение улучшает худший случай задержки G1, параллельно выполняя алгоритм маркировки-сборки-компактации из сборщика G1, который будет запущен, когда параллельные потоки для сборки не могут быстро восстановить память.25. ### Интерфейс сборщика мусора (JEP 304)
Этот JEP – это инновационное изменение. Он улучшает изоляцию кода различных сборщиков мусора, вводя общий интерфейс сборщика мусора. Это изменение обеспечивает лучшую модульность внутреннего кода GC. Это поможет в будущем добавлять новые GC без изменения существующего кодовой базы, а также поможет в удалении или управлении предыдущим GC.26. ### Дополнительные расширения языковых тегов Unicode (JEP 314)
Эта функция улучшает java.util.Locale и связанные с ней API для реализации дополнительных Unicode-расширений языковых тегов BCP 47. Начиная с Java SE 9, поддерживаемые расширения языковых тегов BCP 47 U – “ca” и “nu”. Этот JEP добавит поддержку следующих дополнительных расширений:
- cu (тип валюты)
- fw (первый день недели)
- rg (переопределение региона)
- tz (часовой пояс)
Для поддержки этих дополнительных расширений внесены изменения в различные API для предоставления информации на основе U или дополнительных расширений.
java.text.DateFormat::get*Instance
java.text.DateFormatSymbols::getInstance
java.text.DecimalFormatSymbols::getInstance
java.text.NumberFormat::get*Instance
java.time.format.DateTimeFormatter::localizedBy
java.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern
java.time.format.DecimalStyle::of
java.time.temporal.WeekFields::of
java.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}
java.util.Currency::getInstance
java.util.Locale::getDisplayName
java.util.spi.LocaleNameProvider
Для продвижения OpenJDK и придания ему большей привлекательности для пользователей сообщества, эта функция предоставляет набор корневых сертификатов удостоверяющих центров (CA) по умолчанию в JDK. Это также означает, что бинарные файлы Oracle и OpenJDK будут функционально идентичными. Критические компоненты безопасности, такие как TLS, будут работать по умолчанию в сборках OpenJDK впереди.30. ### Ручные рукопожатия с локальными потоками (JEP 312)
Это внутренняя функция JVM, направленная на улучшение производительности. Операция рукопожатия – это обратный вызов, который выполняется для каждого JavaThread, находящегося в состоянии safepoint. Обратный вызов выполняется либо самим потоком, либо потоком виртуальной машины, удерживая поток в заблокированном состоянии. Эта функция предоставляет способ выполнения обратного вызова на потоках без выполнения глобального safepoint виртуальной машины. Делает возможным и дешевым остановку отдельных потоков, а не только всех или ни одного.31. ### Выделение памяти в альтернативных устройствах (JEP 316)
Приложения стали потреблять больше памяти, наблюдается рост облачных приложений, приложений с встроенными базами данных и потоковых приложений. Для удовлетворения этих услуг существует различные архитектуры памяти. Эта функция улучшает возможности HotSpot VM по выделению кучи Java-объектов на альтернативном устройстве памяти, таком как NV-DIMM, указанном пользователем. Этот JEP нацелен на альтернативные устройства памяти, имеющие те же семантики, что и DRAM, включая семантику атомарных операций, и, следовательно, могут использоваться вместо DRAM для кучи объектов без изменения существующего кода приложения.32. ### Удаление инструмента генерации заголовков нативного кода – javah (JEP 313)
Это изменение управления для удаления инструмента javah из JDK. Функциональность инструмента добавлена в javac
в составе JDK 8, что обеспечивает возможность создавать заголовочные файлы на языке нативного кода во время компиляции, делая javah
бесполезным.35. ### Объединение JDK Forest в единую репозиторию (JEP 296)
За годы существования в JDK были использованы различные репозитории Mercurial. Различные репозитории действительно предоставляли некоторые преимущества, но также имели различные операционные недостатки. В рамках этого изменения множество репозиториев JDK Forest объединены в единую репозиторию для упрощения и оптимизации разработки.36. ### Изменения в API
Java 10 добавил и удалил (да, это не ошибка) API. Java 9 ввела улучшенную устаревшую функцию, где определенные API были отмечены для удаления в будущих версиях. Удаленные API: Вы можете найти удаленные API здесь. Добавленные API: 73 новых API были добавлены в Java 10. Вы можете найти добавленные API вместе с сравнением здесь. Давайте рассмотрим несколько добавлений:
- Добавлены интерфейсы List, Map и Set с методом static copyOf(Collection). Он возвращает неизменяемый список, карту или множество, содержащие предоставленные записи. Для списка, если данный список впоследствии изменяется, возвращенный список не будет отражать такие изменения.
- Optional и его примитивные вариации получают метод orElseThrow(). Это точно то же самое, что и get(), однако в документации по Java указано, что это предпочтительная альтернатива get().
- Класс Collectors получает различные методы для сбора неизменяемых коллекций (Set, List, Map)
List actors = new ArrayList<>();
actors.add("Jack Nicholson");
actors.add("Marlon Brando");
System.out.println(actors); // prints [Jack Nicholson, Marlon Brando]
// Новое добавленное API - Создает неизменяемый список из списка.
List copyOfActors = List.copyOf(actors);
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
// copyOfActors.add("Robert De Niro"); Приведет к
// UnsupportedOperationException
actors.add("Robert De Niro");
System.out.println(actors);// prints [Jack Nicholson, Marlon Brando, Robert De Niro]
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
String str = "";
Optional name = Optional.ofNullable(str);
// Новое добавленное API - предпочтительный вариант, чем метод get()
name.orElseThrow(); // same as name.get()
// Новое добавленное API - Collectors.toUnmodifiableList
List collect = actors.stream().collect(Collectors.toUnmodifiableList());
// collect.add("Tom Hanks"); // Приведет к
// UnsupportedOperationException
Заключение
В этой статье мы рассмотрели различные новые функции, добавленные в Java 10. Если вы считаете, что здесь что-то важное было упущено, пожалуйста, дайте нам знать в комментариях. Как обычно, вы можете проверить полный код на GitHub здесь.
Source:
https://www.digitalocean.com/community/tutorials/java-10-features