90 новых фич (и API) в JDK 11 +21


Привет, Хабр! Представляю вашему вниманию перевод статьи «90 New Features (and APIs) in JDK 11» от автора Simon Ritter.



Новый шестимесячный релизный цикл JDK для многих означает, что некоторые ещё даже не выяснили, какие новые функции в JDK 10, а на пороге уже JDK 11. В одном из ранних блогов (англ.), были перечислены все 109 новых фич и API, которые удалось найти в JDK 10. Поэтому для JDK 11 было решено поступить аналогично. Тем не менее, был выбран другой формат. Этот пост будет поделён на два раздела: новые фичи, которые доступны разработчикам (публичный API) и всё остальное. Таким образом, если вас интересует только то, что непосредственно повлияет на вашу разработку, вы можете пропустить вторую часть.


Общее число изменений, которое удалось подсчитать, получилось равным 90 (это JEP плюс новые классы и методы, исключая отдельные методы для HTTP-клиента и Flight Recorder) (прим. переводчика: Java Flight Recorder (JFR) был одним из коммерческих дополнений от Оракла встроенным в JDK, но начиная с Java 11, благодаря JEP 328, был передан в опенсорс). Хоть и в JDK 11 удалось найти на одиннадцать изменений меньше, чем в JDK 10, считаю, что справедливо сказать, что в JDK 11 добавлено больше функциональных возможностей, однозначно на уровне JVM.


Новые заметные для разработчика фичи


В JDK 11 довольно мало изменений, которые могли бы повлияет на стиль разработки. Присутствует небольшое изменение синтаксиса, множество новых API и возможность запуска приложений одним файлом без использования компилятора (прим. переводчика: так называемые shebang файлы). Кроме того, большим (и ломающим) изменением является удаление агрегирующего модуля java.se.ee, что может повлиять на перенос существующего приложения на JDK 11.


JEP 323: Local-Variable Syntax for Lambda Parameters


В JDK 10 был введен вывод локальных переменных (или вывод типов) (JEP 286). Это упрощает код, поскольку вам больше не нужно явно указывать тип локальной переменной, вместо этого можно использовать var. JEP 323 расширяет использование этого синтаксиса, который теперь также применим к параметрам лямбда-выражений. Простой пример:


            list.stream()
                 .map((var s) -> s.toLowerCase())
                 .collect(Collectors.toList());

Внимательный программист на Java указал бы, что лямбда-выражения уже имеют вывод типа, поэтому использование var было бы (в данном случае) излишним. Мы могли бы так же легко написать тот же код, что и:


            list.stream()
                  .map(s -> s.toLowerCase())
                  .collect(Collectors.toList());

Зачем было нужно добавлять поддержку var? Ответом является один особый случай — когда вы хотите добавить аннотацию к лямбда-параметру. Это невозможно сделать без участия какого-либо типа. Чтобы избежать использования явного типа, мы можем использовать var для упрощения вещей, таким образом:


            list.stream()
                 .map((@Notnull var s) -> s.toLowerCase())
                 .collect(Collectors.toList());

Это изменение потребовало изменений в спецификации языка Java (JLS), в частности:


Страница 24: The description of the var special identifier.
Страница 627-630: Lambda parameters
Страница 636: Runtime evaluation of Lambda expressions
Страница 746: Lambda syntax


JEP 330: Launch Single-File Source-Code Programs


Одним из критических замечаний к Java является избыточность синтаксиса, а «церемония», связанная с запуском даже тривиального приложения, может серьёзно повысить порог входа для новичка. Для написания приложения, которое просто печатает «Hello World!», требуется написать класс с общедоступным статическим void main методом и использовать метод System.out.println(). Сделав это, вы должны скомпилировать код с помощью javac. Наконец, вы cможете запустить приложение, которое будет приветствовать мир. Выполнение того же самого сценария, в большинстве современных языков значительно проще и быстрее.


JEP 330 устраняет необходимость компиляции однофайлового приложения. Теперь достаточно ввести:


            java HelloWorld.java

Java лаунчер идентифицирует, что файл содержит исходный код Java и скомпилирует код в *.class файл перед его выполнением.


Аргументы, помещенные после имени исходного файла, передаются в качестве аргументов при запуске приложения. Аргументы, помещенные перед именем исходного файла, передаются в качестве аргументов java лаунчеру после компиляции кода (это позволяет задавать такие вещи, как classpath, в командной строке). Аргументы, относящиеся к компилятору (например, путь к классам), также будут переданы в javac для компиляции.


Пример:


            java -classpath /home/foo/java Hello.java Bonjour

Будет эквивалентно:


            javac -classpath /home/foo/java Hello.java
            java -classpath /home/foo/java Hello Bonjour

Этот JEP также обеспечивает поддержку «shebang» файлов. Чтобы уменьшить необходимость даже упоминать java лаунчер в командной строке, можно его включить в первую строку исходного файла. Например:


            #!/usr/bin/java --source 11
            public class HelloWorld {
            ...

Флаг -source с используемой версией Java является обязательным.


JEP 321: HTTP Client (Standard)


JDK 9 предоставила новый API для поддержки протокола HTTP Client (JEP 110). Так как JDK 9 предоставила Java Platform Module System (JPMS), этот API был включен как модуль инкубатора. Модули инкубаторов предназначены для предоставления новых API, но не превращают их в стандарт Java SE. Разработчики могут попробовать API, предоставив обратную связь. После внесения необходимых изменений (этот API был обновлен в JDK 10), API можно перенести в основной модуль, чтобы стать частью стандарта.


API HTTP Client теперь является частью стандарта Java SE 11. Это вводит новый модуль и пакет для JDK, java.net.http. Основные классы:


  • HttpClient
  • HttpRequest
  • HttpResponse
  • WebSocket

API можно использовать синхронно или асинхронно. В асинхронном режиме используются CompletionFutures и CompletionStages.


JEP 320: Remove The Java EE and CORBA Modules


С введением JPMS в JDK 9 можно было разделить монолитный файл rt.jar на несколько модулей. Дополнительным преимуществом JPMS является то, что теперь можно создать среду выполнения Java, которая включает только модули, необходимые для вашего приложения, значительно уменьшая общий размер. Имея явно определенные границы, устаревшие модули теперь проще удалять из Java API. Это то, что делает этот JEP; метамодуль java.se.ee включает в себя шесть модулей, которые больше не будут частью стандарта Java SE 11 и не будут включены в JDK.


Удалённые модули:


  • corba (прим. переводчика: rest in peace, burn in hell)
  • transaction
  • activation
  • xml.bind
  • xml.ws
  • xml.ws.annotation

Эти модули были помечены устаревшими (@Deprecated) начиная с JDK 9 и не были включены по умолчанию в компиляцию или рантайм. Если вы пытались скомпилировать или запустить приложение, использующее API из этих модулей на JDK 9 или JDK 10, то потерпели бы неудачу. Если вы используете API из этих модулей в своем коде, вам нужно будет предоставить их в виде отдельного модуля или библиотеки. Судя по отзывам кажется, что модули java.xml, которые являются частью поддержки веб-сервисов JAX-WS, SOAP, — это те, которые вызовут наибольшее количество проблем.


Новый публичный API


Многие новые API-интерфейсы в JDK 11 являются результатом того, что клиентский модуль HTTP теперь является частью стандарта, а также включение Flight Recorder.


Полный схематичный список изменений API, включая сравнение различных версий JDK, можно посмотреть здесь.


Здесь перечислены все новые методы, отличные от тех, которые содержатся в модулях java.net.http и jdk.jfr. Также не перечислены новые методы и классы в модулях java.security, которые довольно специфичны для изменений JEP 324 и JEP 329 (есть шесть новых классов и восемь новых методов).


java.io.ByteArrayOutputStream


  • void writeBytes(byte []): записывает все байты из аргумента в OutputStream

java.io.FileReader


Два новых конструктора, которые позволяют указать Charset.


java.io.FileWriter


Четыре новых конструктора, которые позволяют указать Charset.


java.io.InputStream


  • io.InputStream nullInputStream(): возвращает InputStream, который не считывает байты. Взглянув на этот метод (и на тот, что в OutputStream, Reader и Writer), возникает вопрос, для чего он может пригодиться. Можно думать о них как о /dev/null — для выброса вывода, который вам не нужен, или предоставления ввода, который всегда возвращает нулевые байты.

java.io.OutputStream


  • io.OutputStream nullOutputStream()

java.io.Reader


  • io.Reader nullReader()

java.io.Writer


  • io.Writer nullWriter()

java.lang.Character


  • String toString(int): это перегруженная форма существующего метода, но вместо char используется int. Int — кодовая точка Unicode.

java.lang.CharSequence


  • int compare(CharSequence, CharSequence): сравнивает два экземпляра CharSequence лексикографически. Возвращает отрицательное значение, ноль или положительное значение, если первая последовательность лексикографически меньше, равна или больше второй, соответственно.

java.lang.ref.Reference


  • lang.Object clone(): Должен признаться, это изменение вызывает непонимание. Класс Reference не реализует интерфейс Cloneable, и этот метод выбрасывает исключение CloneNotSupportedException. Должна быть причина для его включения, возможно, для чего-то в будущем. (прим. переводчика: есть обсуждение на StackOverflow, тикет в OpenJDK)

java.lang.Runtime


java.lang.System


Здесь нет новых методов здесь, но стоит упомянуть, что метод runFinalizersOnExit() теперь удален из обоих классов (может возникнуть проблема при миграции на JDK 11).


java.lang.String


Я думаю, что это один из основных моментов новых API в JDK 11. Здесь есть несколько полезных новых методов.


  • boolean isBlank(): возвращает true, если строка пуста или содержит только пробелы, иначе false.
  • Stream lines(): возвращает Stream из String, извлеченных из этой строки, поделенных разделителями строк.
  • String repeat(int): возвращает строку, значение которой представляет собой конкатенацию этой строки, повторяющееся количество раз.
  • String strip(): Возвращает строку, значение которой является этой строкой, при этом удаляются все пробелы в начале и в конце строки.
  • String stripLeading(): возвращает строку, значение которой является этой строкой, при этом удаляются все пробелы в начале строки.
  • String stripTrailing(): возвращает строку, значение которой является этой строкой, при этом удаляются все пробелы в конце строки.

Скорее всего, вы посмотрите на strip() и спросите: «Как это отличается от существующего метода trim()?» Ответ заключается в разнице определения пробелов. (прим. переводчика: если коротко, strip() лучше понимает юникод, подробный разбор на StackOverflow)


java.lang.StringBuffer


java.lang.StringBuilder


Оба этих класса имеют новый метод compareTo(), который принимает StringBuffer/StringBuilder и возвращает int. Метод лексического сравнения аналогичен новому методу compareTo() в CharSequence.


java.lang.Thread


Никаких новых методов. Методы destroy() и stop(Throwable) были удалены. Метод stop(), который не принимает аргументов, все еще присутствует. Может привести к проблеме совместимости.


java.nio.ByteBuffer


java.nio.CharBuffer


java.nio.DoubleBuffer


java.nio.FloatBuffer


java.nio.LongBuffer


java.nio.ShortBuffer


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


java.nio.channels.SelectionKey


  • int interestOpsAnd(int): Атомарно задает интерес этого ключа (key's interest) к побитовому пересечению («и») существующего набора интересов и переданного значения.
  • int interestOpsOr(int): Атомарно задает интерес этого ключа (key's interest) к побитовому объединению («или») существующего набора интересов и переданного значения.

java.nio.channels.Selector


  • int select(java.util.function.Consumer, long): выбор и выполнение действий над ключами, чьи соответствующие каналы готовы для операций ввода-вывода. long аргумент — таймаут.
  • int select(java.util.function.Consumer): то же, что и выше, только без таймаута.
  • int selectNow(java.util.function.Consumer): то же, что и выше, только неблокирующий.

java.nio.file.Files


  • String readString(Path): считывает весь контент из файла в строку, декодируя из байт в символы с использованием кодировки UTF-8.
  • String readString(Path, Charset): как указано выше, с разинцей что декодирование из байт в символы происходит с использованием указанной Charset.
  • Path writeString(Path, CharSequence, java.nio.file.OpenOption []): Запись CharSequence в файл. Символы кодируются в байты, используя кодировку UTF-8.
  • Path writeString(Path, CharSequence, java.nio.file.Charset, OpenOption []): то же, что и выше, символы кодируются в байты, используя кодировку указанную в Charset.

java.nio.file.Path


  • Path of(String, String []): возвращает Path из строкового аргумента пути или последовательности строк, которые при объединении образуют строку пути.
  • Path of(net.URI): возвращает Path из URI.

java.util.Collection


  • Object[] toArray(java.util.function.IntFunction): возвращает массив, содержащий все элементы в этой коллекции, используя предоставленную функцию генерации для аллоцирования возвращаемого массива.

java.util.concurrent.PriorityBlockingQueue


java.util.PriorityQueue


  • void forEach(java.util.function.Consumer): Выполняет передаваемое действие для каждого элемента Iterable до тех пор, пока все элементы не будут обработаны, или действие не выбросит исключение.
  • boolean removeAll(java.util.Collection): удаляет все элементы этой коллекции, которые также содержатся в указанной коллекции (дополнительная операция).
  • boolean removeIf(java.util.function.Predicate): Удаляет все элементы из этой коллекции, которые удовлетворяют заданному предикату.
  • boolean retainAll(java.util.Collection): Сохраняет только те элементы в этой коллекции, которые содержатся в передаваемой коллекции (дополнительная операция).

java.util.concurrent.TimeUnit


  • long convert (java.time.Duration): конвертирует передаваемую Duration в этот тип.

java.util.function.Predicate


  • Predicate not(Predicate): Возвращает предикат, который является отрицанием передаваемого предиката.

Это один из моих любимых новых API в JDK 11. В качестве примера вы можете преобразовать этот код:


    lines.stream()
         .filter(s -> !s.isBlank())

в


    lines.stream()
         .filter(Predicate.not(String::isBlank))

или если мы используем статический импорт:


    lines.stream()
          .filter(not(String::isBlank))

Лично я считаю, что эта версия более понятна и лаконична.


java.util.Optional


java.util.OptionalInt


java.util.OptionalDouble


java.util.OptionalLong


  • boolean isEmpty(): Если значение отсутствует, возвращает true, в противном случае — false.

java.util.regex.Pattern


  • Predicate asMatchPredicate(): Я думаю, что это может быть жемчужина нового API JDK 11. Создает предикат, который проверяет, соответствует ли этот шаблон заданной строке ввода.

java.util.zip.Deflater


  • int deflate(ByteBuffer): сжимает входные данные и заполняет ими указанный буфер.


  • int deflate(ByteBuffer, int): сжимает входные данные и заполняет ими указанный буфер. Возвращает фактическое количество сжатых данных.


  • void setDictionary(ByteBuffer): Устанавливает заданный словарь для сжатия в байты в данном буфере. Это перегруженная форма существующего метода, который теперь может принимать ByteBuffer, а не байтовый массив.


  • void setInput(ByteBuffer): Устанавливает входные данные для сжатия. Также перегруженная форма существующего метода.



java.util.zip.Inflater


  • int inflate(ByteBuffer): распаковывает байты в указанный буфер. Возвращает фактическое количество разархивированных байт.
  • void setDictionary(ByteBuffer): Устанавливает заданный словарь в байты в данном буфере. Перегруженная форма существующего метода.
  • void setInput(ByteBuffer): Устанавливает входные данные для декомпрессии. Перегруженная форма существующего метода.

javax.print.attribute.standard.DialogOwner


Это новый класс в JDK 11. Используется для поддержки запроса на диалог печати или настройки страницы. Должен отображаться поверх всех окон или определенного окна.


javax.swing.DefaultComboBoxModel


javax.swing.DefaultListModel


  • void addAll(Collection): добавляет все элементы, присутствующие в коллекции.
  • void addAll(int, Collection): добавляет все элементы, присутствующие в коллекции, начиная с указанного индекса.

javax.swing.ListSelectionModel


  • int [] getSelectedIndices(): Возвращает массив всех выбранных индексов в выбранной модели, в порядке возрастания.
  • int getSelectedItemsCount(): Возвращает количество выбранных элементов.

jdk.jshell.EvalException


  • jshell.JShellException getCause(): возвращает обёртку throwable cause в исполняющем клиенте, представленным EvalException, или null, если причина не существует или неизвестна.

Новые фичи (не публичный API)


JEP 181: Nest-Based Access Control


Java (и другие языки) поддерживает вложенные классы через внутренние классы. Для правильной работы компилятор должен выполнять некоторые трюки. Например:


   public class Outer {
    private int outerInt;

     class Inner {
       public void printOuterInt() {
         System.out.println("Outer int = " + outerInt);
       }
     }
   }

Компилятор модифицирует это, чтобы создать что-то вроде этого перед выполнением компиляции:


    public class Outer {
      private int outerInt;

      public int access$000() {
        return outerInt; 
      }

    }

    class Inner$Outer {

      Outer outer;

      public void printOuterInt() {
        System.out.println("Outer int = " + outer.access$000());
      }
    }

Хотя, логически, внутренний класс является частью того же самого кода, что и внешний класс, он скомпилирован как отдельный класс. Поэтому для этого требуется синтетический метод ("мост"), который должен быть создан компилятором для обеспечения доступа к приватному полю внешнего класса.


Этот JEP представляет концепцию "гнезда", где два члена одного гнезда (Outer и Inner из нашего примера) являются соседями. Два новых атрибута были добавлены в формата *.class файла: NestHost и NestMembers. Эти изменения также полезны для других, компилируемых в байткод, языков, поддерживающих вложенные классы.


Эта фича предоставляет три новых метода для java.lang.Class:


  • Class getNestHost()
  • Class[] getNestMembers()
  • boolean isNestmateOf(clazz)

Эта функция также потребовала изменений в спецификации виртуальной машины Java (JVMS), в частности в разделе 5.4.4 «Access Control».


JEP 309: Dynamic Class-File Constants


Этот JEP описывает расширение формата *.class файла для поддержки новой формы с константным пулом CONSTANT_Dynamic (часто упоминаемой в презентациях как condy). Идея динамической константы кажется оксюмороном, но, по сути, вы можете думать о ней как о финальном (final) значении в Java. Значение константного пула не задаётся на этапе компиляции (в отличие от других констант), а используется метод начальной загрузки (bootstrap method) для определения значения во время выполнения. Поэтому значение является динамическим, но, поскольку его значение задано только один раз, оно также является константным.


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


Эта фича предоставляет новый класс java.lang.invoke.ConstantBootstraps с девятью новыми методами. Я не буду перечислять их всех здесь; это методы начальной загрузки динамически вычисляемых констант.


Эта фича требовала внесения изменений в JVMS, в частности, в том, как используется специальный байтовый код invoke и раздел 4.4 «The Constant Pool».


JEP 315: Improve Aarch64 Intrinsics


Это был JEP, внесенный Red Hat. JVM теперь может использовать больше специализированных инструкций, доступных в наборе команд Arm 64. В частности, это улучшает работу методов sin(), cos() и log() класса java.lang.Math.


JEP 318: The Epsilon Garbage Collector


Red Hat также внесла свой вклад в этот JEP. Сборщик мусора Epsilon несколько необычен, поскольку он не собирает мусор! Он будет выделять новую память, если это потребуется при создании новых объектов, но не освобождает пространство, занятое объектами без ссылок.


Казалось бы, в чем тогда смысл? Есть, как минимум, два применения:


  • Прежде всего, этот сборщик предназначен для того, чтобы новые алгоритмы GC были оценены с точки зрения их воздействия на производительность. Идея состоит в том, чтобы запустить пример приложения с Epsilon GC и сгенерировать метрику. Включается новый алгоритм GC, запускаются те же тесты и сравниваются результаты.
  • Для очень коротких или маложивущих задач (подумайте о serverless функции в облаке), где вы можете гарантировать, что вы не превысите память, выделенную heap пространству. Это может повысить производительность за счет отсутствия накладных расходов (включая сбор статистики, необходимой для принятия решения о запуске сборщика) в коде приложения.

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


  • Вызывается обычный OutOfMemoryError.
  • Выполнить сброс кучи
  • Сбой жесткого диска JVM и, возможно, выполнение другой задачи (например, запуск отладчика).

JEP 324: Key Agreement with Curve25519 and Curve448


Криптографические стандарты постоянно меняются и совершенствуются. В этом случае существующая схема Диффи-Хеллмана с эллиптической кривой заменяется на Curve25519 и Curve448. Это ключевая схема соглашения, определённая в RFC-7748.


JEP 327: Unicode 10


Платформа Java поддерживает Unicode, для обеспечения обработки всех наборов символов. Поскольку Unicode был обновлен до версии 10, JDK также был обновлен для поддержки этой версии стандарта.


Я всегда заинтригован, чтобы увидеть, что разработчики Unicode включают в новые версии. Unicode 10 имеет 8 518 новых символов. Это включает в себя символ биткоиа, набор символов Nushu (используемый китайскими женщинами для написания стихов), а также Soyombo и Zanabazar Square (являются символами, используемыми в исторических буддийских текстах для написания санскрита, тибетского и монгольского языков). Добавилось также много других Эмоджи, включая долгожданный (по-видимому) Colbert Emoji.


Не забывайте, что начиная с JDK 9 вы можете использовать UTF-8 в файлах свойств (.properties). Это означает, что любой символ Юникода может использоваться в таких файлах. Включая Emojis. Или Nushu.


JEP 328: Flight Recorder


Flight Recorder — это низкоуровневая структура сбора данных для JVM. До JDK 11 это была коммерческая функция в готовом наборе Oracle JDK. Теперь, когда Oracle устраняет функциональные различия между Oracle JDK и OpenJDK, эта функция была внесена в OpenJDK.


JEP выделяет четыре основных свойства:


  • Предоставление API для записи и чтения данных как событий
  • Предоставить буферный механизм и формат двоичных данных?
  • Разрешить настройку и фильтрацию событий?
  • Предоставлять события для ОС, JVM HotSpot и библиотек JDK

Для этого есть два новых модуля: jdk.jfr и jdk.management.jfr.


JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms


Подобно JEP 324, это обновление шифров, используемых JDK. Реализация шифров ChaCha20 и ChaCha20-Poly1305, как указано в RFC 7539. ChaCha20 — это относительно новый потоковый шифр, который может заменить старый, небезопасный шифр потока RC4.


JEP 331: Low-overhead Heap Profiling


Немного удивительно, что это JEP, был внесён Google. Это дает возможность получить информацию о распределении кучи объектов Java в JVM.


Основные свойства:


  • Достаточно низкая рабочая нагрузка, которая будет включена по умолчанию непрерывно
  • Доступен через четко определенный программный интерфейс
  • Может отображать все распределения
  • Может быть определен независимым от реализации способом (то есть, не ограничиваясь конкретным алгоритмом GC или реализацией VM)?
  • Может предоставлять информацию о живых и мертвых объектах Java.

JEP 332: Transport Layer Security (TLS) 1.3


TLS 1.3 (RFC 8446) является "капитальным ремонтом" протокола TLS и обеспечивает значительное повышение безопасности и производительности по сравнению с предыдущими версиями. JDK теперь поддерживает это, хотя это не распространяется на Datagram Transport Layer Security (DTLS).


JEP 333: ZGC A Scalable, Low Latency Garbage Collector


Это новый экспериментальный сборщик мусора, предназначенный для использования с приложениями, для которых требуется большая (многогигабайтная) куча и низкая задержка. Он использует кучу одного поколения (что немного необычно, учитывая общепринятый шаблон использования Weak Generational Hypothesis) и выполняет большинство (но не все) работы GC одновременно с приложением. Это делается используя механизм "барьера" при чтении, который перехватывает каждое чтение объекта из приложения и гарантирует правильность вернувшейся ссылки. Это устраняет проблему одновременного перемещения объектов во время работы потоков приложений.


ZGC — region-based (как и G1), NUMA aware и compacting сборщик мусора. Не предназначен как сборщик общего назначения.


Если вы действительно хотите pauseless сборщик мусора с низкой задержкой, от всего сердца могу порекомендовать C4 в нашей Zing JVM.


JEP 335: Deprecate the Nashorn Scripting Engine


Nashorn был представлен в JDK 8 как более эффективная замена Rhino Javascript движку. Цель состоит в том, чтобы удалить Nashorn вместе с API и jjs инструментом из будущей версии Java. Когда это произойдет, пока не решено. Была предложена возможность использования Graal VM в качестве замены, но как это будет работать, пока неясно.


JEP 336: Deprecate the Pack200 Tools and APIs


Pack200 — это схема сжатия для JAR-файлов, используется ещё со времён Java SE 5.0. С введением JPMS в JDK 9 Pack200 больше не используется для сжатия самого JDK. Инструменты pack200 и unpack200 и API Pack200 в java.util.jar теперь устарели и могут быть удалены в будущей версии JDK. Когда это произойдет, не указано.


Выводы


JDK 11 — следующая версия LTS JDK (так определяет Оракл за которым следуют все остальные). Несмотря на то, что функций, ориентированных на разработчиков, не так много, в JVM много что изменилось, это закладывает основу для будущих более важных функций.


Zulu сборки JDK 11 можно найти здесь и абсолютно бесплатно!


Пришло ли время начать перенос ваших приложений в JDK 11?


(прим. переводчика: просьба, все ошибки перевода и другие неточности присылать в ЛС)




К сожалению, не доступен сервер mySQL