Это раньше новые версии Java появлялись редко и с задержками. Теперь же Oracle успешно держит заданный самой себе ритм «новая Java раз в полгода». Так что несколько дней назад, строго по графику, мы-таки получили Java SE 11 и реализацию JDK (Java Development Kit). Вышла Java 11: новые фичи и возможности  - 1Как всегда, новая версия будет совместима со старыми, а поддержка Java 11 закончится не раньше декабря 2026 года.

Новые фичи Java SE 11 (видимые разработчикам)

Напомним, в Java изменения вносятся посредством внедрения JEP «JDK Enchancement Proposal». JEP — это предложение по улучшению OpenJDK, которое могут утвердить, отложить или отклонить. То есть, по сути, сборник JEP’ов — стратегия развития OpenJDK. В квадратных скобках перед новой «фичей» мы укажем номер соответсвующего JEP. [323] Local-Variable Syntax for Lambda Parameters — var-синтаксис для лямбда-параметров В Java 10 ввели ключевое слово var, которое позволяло не указывать явно тип локальной переменной. Это упрощало код. JEP 323 расширяет возможности использования такого синтаксиса по отношению к лямбда-выражениям. Простой пример:
list.stream ()
                 .map ((var s) -> s.toLowerCase ())
                 .collect (Collectors.toList ());
Как пишет Саймон Риттер, известный Java-евангелист, опытный Java-программист заметит, что использование var в данном случае может быть лишним, поскольку код выше можно заменить следующим:
list.stream ()
                  .map (s -> s.toLowerCase ())
                  .collect (Collectors.toList ());
Зачем, в таком случае, поддерживать var? Просто есть один особый случай — когда вы хотите добавить аннотацию к лямбда-параметру. Это невозможно сделать без участия какого-либо типа, и чтобы не использовать явный тип, мы можем упростить всё с помощью var следующим образом:
list.stream ()
                 .map ((@ Notnull var s) -> s.toLowerCase ())
                 .collect (Collectors.toList ());
[330] Launch Single-File Source-Code Programs Усовершенствование Java-лаунчера для запуска программы в виде единого файла с Java-исходниками Java частенько критикуют за многословный синтаксис и многоступенчатую «церемонию» запуска даже тривиального приложения. Порой это отпугивает новичков. Для написания приложения, которое просто печатает «Hello World!», нужно написать класс с общедоступным статическим void основным методом и использовать метод System.out.println. Сделав это, вы должны скомпилировать код с помощью javac. Наконец, после этого вы можете запустить приложение, которое выведет злополучное приветствие (разумеется, интегрированная среда разработки, как IDEA, так и встроенная в JavaRush, выполняет эту «магию запуска приложения» самостоятельно — прим. ред.). Будем откровенны: в большинстве языков программирования реальный сценарий запуска программ выглядит гораздо проще. JEP 330 устраняет необходимость компиляции однофайлового приложения, поэтому теперь, если вы пользуетесь командной строкой, просто введите
java HelloWorld.java
Лаунчер Java определит, что файл содержит исходный код Java и скомпиллирует код в файл класса перед его выполнением. После или до имени файла с исходным кодом можно поместить параметры. Те, что помещены после имени, передаются в качестве параметров при выполнении приложения. Те, что помещены до имени, передаются в качестве параметров лаунчеру Java после компиляции кода. Параметры, относящиеся к компилятору (например, путь к классам), также будут переданы javac для компиляции. Пример. Строка:
java -classpath / home / foo / java Hello.java Bonjour
будет эквивалентна таким строкам:
javac -classpath / home / foo / java Hello.java
java -classpath / home / foo / java Hello Bonjour
[321] HTTP Client (Standard) — поддержка HTTP Client API стандартизирована В JDK 9 был представлен новый API для поддержки протокола HTTP Client (JEP 110). Поскольку в JDK 9 также внедрили платформу Java Platform Module System (JPMS), этот API был включен как инкубаторный модуль (это модули для предоставления разработчикам новых API, которые ещё не стали стандартом в Java SE, тогда как «действующие» API готовятся к удалению — разработчики могут испытать новые API и попробовать обеспечить обратную связь). После внесения необходимых изменений (этот API был обновлен в JDK 10), API может стать частью стандарта. Так вот, API HTTP Client теперь официально входит в Java SE 11. Это вводит новый модуль и пакет для JDK, java.net.http. Основные новые типы: HttpClient HttpRequest HttpResponse WebSocket Этот API можно использовать синхронно или асинхронно. В асинхронном режиме используются CompletionFutures и CompletionStages. [320] Remove The Java EE and CORBA Modules — удалены модули Java EE и COBRA Вместе с внедрением платформы Java Platform Module System (JPMS) в девятой версии Java, появилась возможность разделить монолитный файл rt.jar на несколько модулей. Кроме того, JPMS позволяет создать среду выполнения Java, которая включает только модули, необходимые для вашего приложения, что существенно уменьшает её размер. С прозрачно определенными границами модулей стало гораздо проще удалить устаревшие части Java API — вот что делает JEP 320. Метамодуль java.se.ee включает в себя шесть модулей, которые не будут входить в стандарт Java SE 11 и не будут включены в JDK:
  • corba
  • transaction
  • activation
  • xml.bind
  • xml.ws
  • xml.ws.annotation
Эти модули объявили устаревшими (deprecated) ещё в JDK 9, и не были включены по умолчанию в компиляцию или выполнение. Это значит, если вы пробовали скомпилировать или запустить приложение, использующее API этих модулей на JDK 9 или JDK 10, у вас ничего не вышло. Если вы используете API этих модулей в своем коде, вам нужно будет предоставить их в виде отдельного модуля или библиотеки.

Новые API

Большое количество новых API в JDK 11 появилось благодаря включению в стандарт языка модуля HTTP Client и Flight Recorder. С полным списком API можно ознакомиться в следующем полном и обстоятельном сравнении разных версий JDK, составленном Гуннаром Морлингом. А в этой заметке перечислим некоторые новые методы, которые не входят в модули java.net.http, jdk.jfr и java.security. java.lang.String Возможно, изменение в String — одно из самых важных в API JDK 11. Здесь есть несколько полезных новых методов.
  • boolean isBlank (): возвращает true, если строка пуста или содержит только пробелы, иначе false.

  • Stream lines(): возвращает поток строк, извлеченных из этой строки, разделенных терминаторами строк.

  • String repeat (int): возвращает строку, значение которой представляет собой конкатенацию этой строки, повторяющуюся int раз.

  • String strip (): Возвращает строку, из которой удалены все пробелы, которые находятся до первого символа, не являющегося пробелом, или после последнего.

  • String stripLeading (): Возвращает строку, из которой удалены все пробелы, которые находятся до первого символа, не являющегося пробелом.

  • String stripTrainling (): Возвращает строку, из которой удалены все пробелы, которые находятся после последнего символа, не являющегося пробелом.
Что-то похожее на strip() уже делал метод trim (), только вот под пробелами эти методы понимают разные вещи. В случае trim() отсекаются только пробелы, а в strip() — ещё и спецсимволы, вроде табуляции. java.lang.StringBuffer java.lang.StringBuilder Оба этих класса содержат новый метод compareTo (), который принимает StringBuffer/StringBuilder и возвращает int. Метод лексического сравнения аналогичен новому методу compareTo() CharSequence. java.io.ByteArrayOutputStream
  • void writeBytes (byte []): записывает все байты параметра в выходной поток java.io.FileReader
Здесь появилось два новых конструктора, которые позволяют указать Charset. java.io.FileWriter Четыре новых конструктора, которые позволяют указать Charset. java.io.InputStream
  • io.InputStream nullInputStream (): возвращает InputStream, который не считывает байты. Как использовать этот метод? Можете считать его чем-то вроде /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.
java.lang.CharSequence
  • int compare (CharSequence, CharSequence): лексикографически сравнивает два экземпляра CharSequence. Возвращает отрицательное значение, нуль или положительное значение, если первая последовательность лексикографически меньше, равна или больше второй, соответственно.
java.lang.ref.Reference
    lang.Object clone (): евангелист Java Саймон Риттер признается, что этот метод его смущает. Класс Reference не реализует интерфейс Cloneable, и этот метод всегда будет генерировать исключение CloneNotSupportedException. Однако эксперт предполагает, что этот метод пригодится для чего-то в будущем.
java.lang.Runtime java.lang.System Здесь новых методов нет. Упомянем только, что метод runFinalizersOnExit () удален из обоих этих классов, что может вызвать проблемы с совместимостью. 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)

  • int interestOpsOr (int)
java.nio.channels.Selector
  • int select (java.util.function.Consumer, long): выбирает и исполняет действие на клавишах, соответствующие каналы которых готовы для операций ввода-вывода. Параметр long — это тайм-аут.

  • int select (java.util.function.Consumer): работает, как метод выше, только без таймаута.

  • int selectNow (java.util.function.Consumer): работает, как метод выше, только он non-blocking.

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
  • Путь (String, String []): возвращает путь (Path), преобразуя строку пути или последовательность строк, которые при объединении образуют строку пути.

  • Путь (net.URI): возвращает путь преобразуя 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): конвертирует заданную продолжительность времени в этот юнит.
java.util.function.Predicate
  • Predicate not(Predicate): возвращает предикат, который является отрицанием поставленного предиката.
Например, следующий код:
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 (): эксперт по Java Саймон Риттер полагает, что здесь может быть скрыто настоящее сокровище 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
  • shell.JShellException getCause (): возвращает причину throwable в исполняющем клиенте, представленном этим EvalException, или null, если причины не существует или она неизвестна.

Недевелоперские фичи Java 11

[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());
      }
    }
Хотя по логике внутренний класс является частью того же самого кода, что и внешний класс, он скомпилирован как отдельный класс. Поэтому для этой операции требуется синтетический соединительный метод, который должен создать компилятором для обеспечения доступа к private-полю внешнего класса. Этот JEP представляет концепцию вложений (гнёзд), где два члена одного вложения (Outer and Inner из нашего примера) являются «друзьями по вложению». Для формата файла класса определены два новых атрибута — NestHost и NestMembers. Эти изменения полезны для других языков, поддерживающих вложенные классы и байткод. Эта функция представляет три новых метода для java.lang.Class: Class getNestHost () Class [] getNestMembers () boolean isNestmateOf (Class) [309] Dynamic Class-File Constants Этот JEP описывает расширение формата файла класса для поддержки новой формы с постоянным пулом CONSTANT_Dynamic. Идея динамической константы кажется оксюмороном, но, по сути, вы можете думать о ней как о конечном значении в Java 11. Значение константы-пула не задано во время компиляции (в отличие от других констант), но использует метод начальной загрузки для определения значения во время выполнения. Поэтому значение является динамическим, но, поскольку его значение задано только один раз, оно также является постоянным. Эта функция в первую очередь нацелена на людей, разрабатывающих новые языки и компиляторы, которые будут генерировать байт-коды и файлы классов в качестве вывода для запуска на JVM. [315] Improve Aarch64 Intrinsics Этот JEP предложило сообщество Red Hat. Теперь JVM может использовать больше специализированных инструкций, доступных в наборе команд Arm 64. В частности, это улучшает работу методов sin (), cos () и log () класса java.lang.Math. [318] Epsilon: A No-Op Garbage Collector Как и в случае JEP 315, за появление сборщика мусора Epsilon можете благодарить Red Hat. Epsilon необычен хотя бы тем, что на самом деле он мусор не собирает! При создании новых объектов, он выделяет память, если это нужно, но не восстанавливает пространство, занятое незарегистрированными объектами. «И в чём смысл?», — спросите вы. Оказывается у такой «сборки мусора» есть два вида использования:
  1. Прежде всего, этот сборщик мусора предназначен для того, чтобы новые алгоритмы GC были оценены с точки зрения их влияния на производительность. Идея состоит в том, чтобы запустить пример приложения с Epsilon и сгенерировать набор показателей. Включается новый алгоритм сборки мусора, запускаются те же тесты, а затем результаты сравниваются.

  2. Для очень коротких задач (считайте безсерверные функции в облаке), где вы можете гарантировать, что не превысите память, выделенную куче. Это может повысить производительность за счет отсутствия накладных расходов (включая сбор статистики, необходимой для принятия решения о запуске коллектора) в коде приложения. Если пространство кучи исчерпано, JVM может быть сконфигурирован с ошибкой одним из трех способов:
    • Вызывается обычный OutOfMemoryError.
    • Выполнить сброс кучи
    • Сбой жесткого диска JVM и, возможно, выполнение другой задачи (например, запуск отладчика).
[328]: Flight Recorder Flight Recorder — это низкоуровневая структура сбора данных для JVM. До JDK 11 это была коммерческая функция в Oracle JDK binary. Теперь Oracle устраняет функциональные различия между Oracle JDK и одним билдом из OpenJDK. Вот что делает Flight Recorder:
  • Предоставляет API для производства и потребления данных как событий
  • Предоставляет буферный механизм и формат двоичных данных
  • Разрешает настройку и фильтрацию событий
  • Предоставлять события для ОС, JVM HotSpot и библиотек JDK
Здесь появилось два новых модуля: jdk.jfr и jdk.management.jfr. [329] Криптографические алгоритмы ChaCha20 и Poly1305 Этот JEP посвящен обновлению шифров, используемых JDK. В данном случае реализованы алгоритмы шифрования ChaCha20 и ChaCha20-Poly1305, как указано в RFC 7539. ChaCha20 — это относительно новый потоковый шифр, который может заменить старый, небезопасный шифр RC4. [333] ZGC: A Scalable Low-Latency Garbage Collector Экспериментальный масштабируемый сборщик мусора с низкой задержкой. Предназначен для использования с приложениями, для которых требуется большая (многогигабайтная) куча и низкая задержка. Он использует кучу одного поколения и выполняет большинство (но не все) работы по сборке мусора одновременно с приложением. [332] Transport Layer Security (TLS) 1.3 TLS 1.3 (RFC 8446) — серьезная заплата протокола защиты транспортного уровня TLS, которая обеспечивает значительное повышение безопасности и производительности по сравнению с предыдущими версиями. JDK теперь поддерживает эту версию протокола. Материал основан на статье Саймона Риттера и официальной документации.