Поиск по сайту:

Особенности Java 15


В соответствии с традицией шестимесячного цикла, после выпуска Java 14 17 марта 2020 г. у нас теперь есть Java 15, следующая не-LTS-версия, выпущенная 15 сентября 2020 г.

Особенности Java 15

Вот краткий обзор функций, которые являются частью Java 15:

  • Закрытые классы (предварительная версия) — JEP 360
  • Сопоставление с образцом для instanceof (вторая предварительная версия) — JEP 375
  • Записи (вторая предварительная версия) — 359 японских японских японских юаней
  • Текстовые блоки (стандарт) — 378 JEP
  • Скрытые классы — 371 JEP
  • Удаление механизма JavaScript Nashorn – JEP 372
  • Повторная реализация устаревшего API DatagramSocket — JEP 373
  • Отключение и прекращение предвзятой блокировки – JEP 374
  • Шенандоа: сборщик мусора с малой паузой – 379 JEP
  • Удаление портов Solaris и SPARC – JEP 381
  • API доступа к внешней памяти (второй инкубатор) — JEP 383
  • Устаревшая активация RMI для удаления – JEP 385

Настройка установки Java 15 в Mac OS

  • Чтобы начать работу с Java 15, загрузите JDK отсюда.
  • Скопируйте и извлеките файл tar в /Library/Java/JavaVirtualMachines, как показано ниже:

$ cd /Library/Java/JavaVirtualMachines

$ sudo cp ~/Downloads/openjdk-15_osx-x64_bin.tar.gz /Library/Java/JavaVirtualMachines

$ sudo tar xzf openjdk-15_osx-x64_bin.tar.gz

$ sudo rm openjdk-15_osx-x64_bin.tar.gz

После этого откройте bash_profile с помощью любого текстового редактора. Я использую vim ~/.bash_profile. Установите путь Java15 к JAVA_HOME, сохраните изменения и выполните source ~/.bash_profile, чтобы отразить изменения.

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-15.jdk/Contents/Home

Наконец, вы готовы компилировать и запускать программы с использованием Java 15. Мы будем использовать JShell, интерактивный инструмент командной строки REPL для быстрого тестирования новых функций Java 15.

Важно отметить, что многие функции, выпущенные в Java 15, находятся в предварительной версии. Это означает, что хотя сейчас они полностью работают, в будущем все может измениться. Некоторые из них можно сделать стандартными или просто удалить в следующих циклах выпуска. Чтобы протестировать функции предварительного просмотра, вам необходимо явно установить --enable-preview при запуске программы JShell или Java, как показано ниже:

jshell --enable-preview

javac --release 15 --enable-preview Author.java

В следующих нескольких разделах давайте обсудим существенные языковые изменения в Java 15.

1. Запечатанные классы (предварительная версия)

Запечатанные классы были в Kotlin уже некоторое время, и в Java 15 наконец появилась эта функция для лучшего контроля над наследованием.

Как следует из названия, классы Sealed позволяют вам ограничивать или разрешать иерархию классов только для определенных типов.

Это невероятно полезно для сопоставления с образцом, поскольку у вас есть определенное количество классов, между которыми можно переключаться.

Следующий синтаксис определяет запечатанный класс в Java 15:

public sealed class Vehicle permits Car, Bike, Truck {
...
}

Таким образом, приведенный выше код означает, что только классы, определенные после ключевого слова permits, могут расширять класс Vehicle sealed.

В случае, если вы определили классы Автомобиль, Велосипед и Грузовик в том же файле, что и Автомобиль, вы можно опустить разрешение ключевого слова, и компилятор позаботится об этом неявно, как показано ниже:

sealed class Vehicle {...}

final class Car extends Vehicle {...}
final class Bike extends Vehicle {...}
final class Truck extends Vehicle {...}

Как вы можете видеть выше, мы определили конечный модификатор каждого из классов. Теперь, это важное правило запечатанного класса, которое вы должны иметь в виду: каждый разрешенный класс должен быть установлен с явным модификатором. Он может быть либо окончательным, либо запечатанным, либо незапечатанным.

Вот как каждый из модификаторов влияет на наследование:

  • Разрешенный подкласс, объявленный final, не может быть расширен дальше.
  • Разрешенный подкласс, объявленный sealed, может быть расширен, но только классами, разрешенными подклассом.
  • Разрешенный подкласс может быть объявлен незапечатанным и может быть расширен любым классом. Суперкласс не может ограничивать подклассы ниже по иерархии классов.

До Java 15 разработчики могли использовать только ключевое слово final или модификаторы области для управления наследованием. Таким образом, запечатанные классы предоставляют Java-разработчикам дополнительную гибкость при определении иерархии классов.

Java Reflection API также получает два новых метода для работы с запечатанными классами:

java.lang.constant.ClassDesc[] getPermittedSubclasses();

boolean isSealed()

2. Записи (второе превью)

Записи были введены в качестве функции предварительного просмотра в Java 14, чтобы сократить шаблонный код при написании классов носителей данных на основе POJO. Это то, что давно присутствует в Kotlin в виде классов данных.

Теперь, с Java 15, Records получает вторую предварительную версию. Хотя серьезных изменений нет (лишь несколько незначительных дополнений), все же есть несколько важных уточнений и ограничений, о которых вам следует знать:

  • До Java 15 можно было объявлять нативные методы в записях (хотя это было плохой идеей). Теперь JEP прямо запрещает объявлять нативные методы в записях. Понятно, что определение метода native крадет УТП записей, вводя зависимость от внешнего состояния.
  • Неявно объявленные поля, соответствующие компонентам записи класса записи, являются final и теперь не должны изменяться с помощью отражения, так как это вызовет IllegalAccessException.

Записи должны быть классами-носителями данных, и вам следует полностью избегать определения в них нативных методов.

Записи с запечатанными типами

Мы знаем, что записи являются окончательными и не могут быть продлены. К счастью, записи могут реализовывать интерфейсы.

Таким образом, вы можете определить запечатанный интерфейс и реализовать его в своих записях следующими способами:

sealed interface Car permits BMW, Audi { ... }

record BMW(int price) implements Car { ... }

record Audi(int price, String model) implements Car { ... }

Местные рекорды

Записи также могут быть определены в методах для хранения промежуточных значений. В отличие от локальных классов, локальная запись неявно статична. Это означает, что они не могут получить доступ к переменным и членам экземпляров окружающих методов, что на самом деле здорово, поскольку предотвращает захват значений записью.

Локальные записи являются большим подспорьем для разработчиков Java, которым раньше приходилось создавать вспомогательные записи.

Посмотрите, как введение локальных записей помогает выполнять вычисление значений в потоковом API с помощью следующего метода:

List<Merchant> findTopMerchants(List<Merchant> merchants, int month) {
    // Local record
    record MerchantSales(Merchant merchant, double sales) {}

    return merchants.stream()
        .map(merchant -> new MerchantSales(merchant, computeSales(merchant, month)))
        .sorted((m1, m2) -> Double.compare(m2.sales(), m1.sales()))
        .map(MerchantSales::merchant)
        .collect(toList());
}

Заключение

В то время как вышеупомянутые две были двумя основными языковыми функциями в Java 15, у нас также есть сопоставление с образцом во втором предварительном просмотре для отзывов пользователей, текстовые блоки в качестве стандартной функции и, что наиболее важно, новая функция скрытых классов.

Скрытые классы — это функция JVM, актуальная для разработчиков фреймворков. Это позволяет сделать реализацию класса невозможной для обнаружения, определив ее с помощью Lookup::defineHiddenClass. При этом такие классы нельзя найти ни с помощью Class.forName, ни со ссылкой на них в байт-коде.

Это основные изменения, внесенные в Java 15.