[Перевод] Что нового в Java 15?
Скрытые классы, изолированные классы, текстовые блоки, записи и EdDSA: в JDK 15 имеется много ценного.
Как гласит одно из моих любимых выражений, в Java 15 присутствует много богатого шоколадного добра. В новую версию (релиз 15 сентября 2020 г.) включены 14 важных изменений (JEP), направленных на совершенствование JDK. В этой статье дается краткий обзор новинок на основе информации, содержащейся в JEP.
14 JEP можно разделить на пять групп. Для более подробного изучения смотрите документацию по каждому из них.
Новый функционал, захватывающий дух:
- JEP 339: алгоритм цифровой подписи на основе кривой Эдвардса (EdDSA)
- JEP 371: скрытые классы
Дополнения к существующему стандартному функционалу Java SE:
- JEP 378: текстовые блоки
- JEP 377: сборщик мусора типа Z (ZGC)
- JEP 379: Shenandoah — сборщик мусора с малым временем паузы
Улучшение устаревшего функционала Java SE:
- JEP 373: переработка устаревшего DatagramSocket API
С нетерпением ждем новинок:
- JEP 360: изолированные классы (предварительная версия)
- JEP 375: сопоставление с образцом для instanceof (вторая предварительная версия)
- JEP 384: записи (вторая предварительная версия)
- JEP 383: API доступа к внешней памяти (вторая инкубаторная функция)
Удаление и прекращение поддержки:
- JEP 372: удаление Nashorn JavaScript Engine
- JEP 374: отключение и исключение тенденциозной блокировки
- JEP 381: удаление портов Solaris и SPARC
- JEP 385: исключение RMI активации при удалении
Новый функционал, захватывающий дух
Алгоритм цифровой подписи на основе кривой Эдвардса (JEP 339). Я буду первым, кто признает, что алгоритм цифровой подписи Edwards-Curve (EdDSA), немного выходит за рамки моих знаний о шифровании. Ладно, я вообще ничего про это не знаю. Однако, этот JEP разработан как платформо-независимая реализация EdDSA с лучшей производительностью, чем существующая реализация на языке C — ECDSA.
В соответствии с документацией JDK, EdDSA — современная схема подписи с эллиптической кривой, которая имеет несколько преимуществ по сравнению с существующими в JDK.
Цели реализации:
- Основная цель этого JEP — реализация схемы подписи так, как это стандартизировано в RFC 8032. При этом новая схема не заменяет ECDSA.
- Разработка платформо-независимой реализации EdDSA с более высокой производительностью, чем существующая реализация ECDSA при той же степени безопасности. Например, EdDSA, использующий Curve25519 при ~126 битах защиты, должен быть таким же быстрым, как ECDSA, использующий кривую secp256r1 при ~128 битах защиты.
- Помимо этого, реализация не будет содержать секретных областей. Эти свойства важны для предотвращения сторонних атак.
Теперь вы знаете больше, чем я. В скором времени ожидайте статью в журнале Java Magazine, объясняющую EdDSA.
Скрытые классы (JEP 371) — это классы, которые не могут быть задействованы непосредственно байт-кодом других классов. Они предназначены для использования фреймворками, которые динамически создают классы во время выполнения и используют их косвенно через механизм рефлексии. Динамически сгенерированные классы могут потребоваться только в течение ограниченного промежутка времени, поэтому сохранение их на время существования статически сгенерированного класса может излишне увеличить объем памяти.
Динамически сгенерированные классы также нельзя обнаружить. Обнаружение таких классов по имени было бы пагубным, поскольку это подрывает их назначение, заключающееся в том, что они являются просто деталью реализации статически сгенерированного класса.
Релиз скрытых классов закладывает основу отказа от использования разработчиками нестандартного API sun.misc.Unsafe: defineAnonymousClass. Oracle намеревается исключить и удалить этот класс в будущем.
Дополнения к существующим стандартам Java SE
Текстовые блоки (JEP 378), пришедшие из Project Amber, после двух предварительных версий в JDK 13 и 14 окончательно зарелизились. Целью их создания стало желание разработчиков уменьшить трудности объявления и использования многострочных строковых литералов в Java.
Текстовые блоки автоматически форматируют строки предсказуемым образом, но если этого недостаточно, разработчик может взять форматирование на себя. Во второй версии предварительного функционала представлены две новые escape-последовательности для управления новыми строками и пробелами. Например, \
Раньше, чтобы вывести одну длинную строку текста, вам пришлось бы написать так:
Использование \ упрощает чтение кода:
Управляющая последовательность \s может предотвратить удаление конечных пробелов. Таким образом, следующий текст представляет три строки, каждая из которых состоит ровно из пяти символов. (В средней строке, соответствующей зеленому цвету, \s не используется, потому что в ней и так пять символов.)
Сборщик мусора типа Z (JEP 377) был представлен в JDK 11 в качестве экспериментального функционала. Теперь он получил официальный статус. ZGC — это параллельный, поддерживающий NUMA, масштабируемый сборщик мусора с малой задержкой, предназначенный для предоставления пауз при сборке мусора менее 10 миллисекунд даже в многотерабайтных кучах. Среднее время паузы, согласно тестам Oracle, составляет менее 1 миллисекунды, а максимальное — менее 2 миллисекунд. На рисунке 1 показано сравнение параллельного сборщика мусора Java, G1 и ZGC, при этом время паузы ZGC увеличено в 10 раз.
Рисунок 1. Сравнение времени паузы сборщиков мусора
Тем не менее, для многих нагрузок G1 (который по-прежнему используется по умолчанию) может быть немного быстрее, чем ZGC. Кроме того, для очень маленьких куч, таких как те, которые составляют всего несколько сотен мегабайт, G1 также может быть быстрее. Таким образом, вам рекомендуется провести свои собственные тесты со своими нагрузками, чтобы увидеть, какой сборщик мусора использовать.
Важно: поскольку ZGC больше не является экспериментальным, вам не нужно использовать
-XX:+UnlockExperimentalVMOptions для его использования.
И хотя я говорю о сборщиках мусора со сверхнизким временем паузы, Shenandoah (JEP 379) теперь является стандартной функцией JDK 15. Он был экспериментальным, начиная с JDK 12. Теперь, как и в случае с ZGC, вам не нужно использовать -XX:+UnlockExperimentalVMOptions.
Shenandoah фокусируется на выполнении сборки мусора одновременно с запущенной программой Java, чтобы время паузы больше не было прямо пропорционально размеру кучи. Подумайте об использовании Shenandoah, если приложение имеет большую многогигабайтную кучу и если переменное время паузы при сборке мусора создает проблемы для сценариев использования приложения.
Модернизация устаревшего функционала Java SE
Переработка устаревшего DatagramSocket API (JEP 373). Считайте, что это в основном рефакторинг некоторого кода юрского периода, поскольку этот JEP заменяет старые, трудно поддерживаемые реализации API-интерфейсов java.net.DatagramSocket и java.net.MulticastSocket более простыми и современными реализациями, которые легко поддерживать и отлаживать, и которые будут работать с виртуальными потоками Project Loom.
Поскольку существует очень много кода, использующего старый API (c JDK 1.0), устаревшая реализация не будет удалена. Фактически, новое специфичное для JDK системное свойство, jdk.net.usePlainDatagramSocketImpl, настраивает JDK для использования устаревшей реализации, если рефакторинг API вызывает проблемы при регрессионных тестах или в некоторых случаях.
С нетерпением ждем новинок
Изолированные классы (JEP 360). Первая предварительная версия, созданную в Project Amber. Изолированные классы и интерфейсы ограничивают их расширение или реализацию другими классами. Почему это важно? Разработчик может захотеть управлять кодом, который отвечает за реализацию определенного класса или интерфейса. Изолированные классы предоставляют более декларативный способ, чем модификаторы доступа для ограничения использования суперкласса. Например:
Цель изолирования класса — позволить клиентскому коду понимать, какие подклассы разрешены. В конце концов, могут быть такие случаи использования, когда ожидается, что исходное определение класса (или интерфейса) будет полностью исчерпывающим, и когда разработчик не разрешает его расширение только там, где это разрешено.
Для изолированных классов существуют некоторые ограничения:
- Изолированный класс и его разрешенные подклассы должны принадлежать тому же самому модулю, и, если они объявлены в модуле без имени, должны существовать в одном пакете.
- Каждый разрешенный подкласс должен напрямую расширять изолированный класс.
- Каждый разрешенный подкласс должен выбрать модификатор, чтобы описать, как он продолжает изолирование, инициированное его суперклассом — финальный, изолированный или неизолированный (изолированный класс не может помешать его разрешенным подклассам сделать это).
Сопоставление с образцом для instanceof (JEP 375). Вторая предварительная версия — еще одна разработка Project Amber. Первая предварительная версия функционала была в Java 14 и по сравнению с ней нет никаких изменений.
Цель — улучшить Java за счет сопоставления с образцом для оператора instanceof. Это позволяет более кратко и безопасно выразить общую логику в программе, а именно условное извлечение компонентов из объектов. Позвольте мне отослать вас к отличной статье Мала Гупта «Сопоставление с образцом для instanceof в Java 14» в качестве примера.
Записи (JEP 384), вторая предварительная версия. Записи — это классы, которые действуют как прозрачные носители неизменяемых данных. Новый JEP включает уточнения, основанные на отзывах сообщества, и поддерживает несколько новых дополнительных форм локальных классов и интерфейсов. Записи также поступают от Project Amber.
Классы записи представляют собой объектно-ориентированную конструкцию, которая выражает простую агрегацию значений. Таким образом, они помогают программистам сосредоточиться на моделировании неизменяемых данных, а не на расширяемом поведении. Записи автоматически реализуют методы, управляемые данными, такие как метод equals и методы доступа, а также, записи сохраняют давние принципы Java, такие как номинальная типизация и совместимость миграции. Другими словами, они упрощают кодирование и чтение классов, содержащих неизменяемые данные.
Доступ к внешней памяти (JEP 383) — это вторая инкубаторная версия API, которая позволяет программам Java безопасно и эффективно обращаться к внешней памяти вне кучи Java. Цель состоит в том, чтобы начать замену java.nio.ByteBuffer и sun.misc.Unsafe. Это часть проекта Panama, который улучшает связь между Java и другими API.
В JEP метко описывается необходимость этого нововведения следующим образом:
Когда дело доходит до доступа к внешней памяти, разработчики сталкиваются с дилеммой — должны ли они выбрать безопасный, но ограниченный (и, возможно, менее эффективный) путь, такой как ByteBuffer API, или они должны отказаться от гарантий безопасности и принять опасный и неподдерживаемый Unsafe API?
Этот JEP представляет безопасный, поддерживаемый и эффективный API для доступа к внешней памяти. Предоставляя целевое решение проблемы доступа к внешней памяти, разработчики будут освобождены от ограничений и опасностей существующих API. Они также получат улучшенную производительность, поскольку новый API будет разрабатываться с нуля с учетом оптимизации JIT.
Удаление и прекращение поддержки
Ни одно из этих решений не должно вызывать споров.
Удаления движка Nashorn JavaScript (JEP 372). Данный движок, его API и инструмент jjs были объявлены устаревшими еще в Java 11. Пришло время попрощаться.
Отключение и исключение тенденциозной блокировки (JEP 374) позволяет избавиться от старого метода оптимизации, используемого в JVM HotSpot для уменьшения накладных расходов, связанных с неконтролируемой блокировкой. Данная блокировка исторически приводила к значительному повышению производительности по сравнению с обычными методами блокировки, но прирост производительности, наблюдаемый в прошлом, сегодня гораздо менее очевиден. Стоимость выполнения атомарных инструкций на современных процессорах снизилась.
Тенденциозная блокировка привела к появлению большого количества сложного кода, и эта сложность мешает команде разработчиков Java вносить существенные изменения в подсистеме синхронизации. Отключив блокировку, и оставив на усмотрение программиста возможность ее повторного включения, команда разработчиков Java надеется определить, будет ли разумным полностью удалить ее в будущем выпуске.
Удаление портов Solaris и SPARC (JEP 381). В данном случае удалению подлежит весь исходный код, специфичный для операционной системы Solaris и архитектуры SPARC. Больше нечего сказать.
Исключение RMI активации при удалении (JEP 385). Упрощает Java, удаляя устаревшую часть вызова удаленных методов, которая стала опциональной, начиная с Java 8.
Использование активации RMI уменьшается и сокращается. Команда Java не видит свидетельств того, чтобы какие-либо новые приложения были написаны с ее использованием, и есть свидетельства того, что очень немногие существующие приложения используют активацию RMI. Поиск по различным базам кода с открытыми исходниками почти не выявил упоминания каких-либо API, связанных с ней. Никаких отчетов об ошибках активации RMI, генерируемых извне, не поступало в течение нескольких лет.
Поддержка активации RMI как части платформы Java требует постоянных затрат на обслуживание. Это добавляет сложности для RMI. Активацию RMI можно удалить, не затрагивая остальную часть RMI. Ее удаление не снижает ценности Java для разработчиков, но снижает затраты на долгосрочное обслуживание JDK.
Заключение
Java 15 продолжает шестимесячный цикл выпуска новых версий и представляет собой среднего размера релиз, полезный для большинства разработчиков.