Это раньше новые версии Java появлялись редко и с задержками. Теперь же Oracle успешно держит заданный самой себе ритм «новая Java раз в полгода». Так что несколько дней назад, строго по графику, мы-таки получили Java SE 11 и реализацию JDK (Java Development Kit).
Как всегда, новая версия будет совместима со старыми, а поддержка 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
Новые 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
Четыре новых конструктора, которые позволяют указать Charse
t.
java.io.InputStream
io.InputStream nullInputStream ()
: возвращаетInputStream
, который не считывает байты. Как использовать этот метод? Можете считать его чем-то вроде /dev/null для выбрасывания ненужного вам вывода или для внедрения ввода, который всегда возвращает нуль байтов.
io.OutputStream nullOutputStream ()
io.Reader nullReader ()
io.Writer nullWriter ()
String toString (int)
: это перегруженная форма существующего метода, но вместо char используется int.
int compare (CharSequence, CharSequence)
: лексикографически сравнивает два экземпляраCharSequence
. Возвращает отрицательное значение, нуль или положительное значение, если первая последовательность лексикографически меньше, равна или больше второй, соответственно.
lang.Object clone ()
: евангелист Java Саймон Риттер признается, что этот метод его смущает. Класс Reference
не реализует интерфейс Cloneable
, и этот метод всегда будет генерировать исключение CloneNotSupportedException
. Однако эксперт предполагает, что этот метод пригодится для чего-то в будущем.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)
int select (java.util.function.Consumer, long)
: выбирает и исполняет действие на клавишах, соответствующие каналы которых готовы для операций ввода-вывода. Параметр long — это тайм-аут.int select (java.util.function.Consumer)
: работает, как метод выше, только без таймаута.int selectNow (java.util.function.Consumer)
: работает, как метод выше, только он non-blocking.
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
.
- Путь (String, String []): возвращает путь (Path), преобразуя строку пути или последовательность строк, которые при объединении образуют строку пути.
- Путь (net.URI): возвращает путь преобразуя URI.
Object [] toArray (java.util.function.IntFunction)
: возвращает массив, содержащий все элементы в этой коллекции, используя предоставленную генераторную функцию для распределения возвращаемого массива.
void forEach (java.util.function.Consumer)
: выполняет заданное действие для каждого элемента Iterable до тех пор, пока все элементы не будут обработаны, или действие не вызовет исключение.boolean removeAll (java.util.Collection)
: удаляет все элементы этой коллекции, которые также содержатся в указанной коллекции (дополнительная операция).boolean removeIf (java.util.function.Predicate)
: Удаляет все элементы этой коллекции, которые удовлетворяют заданному предикату.boolean retainAll (java.util.Collection)
: Сохраняет только элементы в этой коллекции, которые содержатся в указанной коллекции (дополнительная операция).
long convert (java.time.Duration)
: конвертирует заданную продолжительность времени в этот юнит.
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.
Predicate asMatchPredicate ()
: эксперт по Java Саймон Риттер полагает, что здесь может быть скрыто настоящее сокровище API JDK 11. Этот метод создает предикат, который проверяет, соответствует ли этот шаблон заданной строке ввода.
int deflate (ByteBuffer)
: сжимает входные данные и заполняет указанный буфер сжатыми данными.int deflate (ByteBuffer, int)
: сжимает входные данные и заполняет указанный буфер сжатыми данными. Возвращает фактическое количество сжатых данных.void setDictionary (ByteBuffer)
: устанавливает заданный словарь для сжатия в байты в данном буфере. Это перегруженная форма существующего метода, который теперь может приниматьByteBuffer
, а не байтовый массив.void setInput (ByteBuffer)
: Устанавливает входные данные для сжатия. Также является перегруженной формой существующего метода.
int inflate (ByteBuffer)
: распаковывает байты в указанный буфер. Возвращает фактическое количество несжатых байтов.void setDictionary (ByteBuffer)
: устанавливает заданный словарь в байты в данном буфере. Является перегруженной формой существующего метода.void setInput (ByteBuffer)
: устанавливает входные данные для декомпрессии. Перегруженная форма существующего метода.
void addAll (Collection)
: добавляет все элементы, присутствующие в коллекции.void addAll (int, Collection)
: добавляет все элементы, присутствующие в коллекции, начиная с указанного индекса.
int [] getSelectedIndices ()
: возвращает массив всех выбранных индексов в выбранной модели в порядке возрастания.int getSelectedItemsCount ()
: возвращает количество выбранных элементов.
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 необычен хотя бы тем, что на самом деле он мусор не собирает! При создании новых объектов, он выделяет память, если это нужно, но не восстанавливает пространство, занятое незарегистрированными объектами.
«И в чём смысл?», — спросите вы. Оказывается у такой «сборки мусора» есть два вида использования:
- Прежде всего, этот сборщик мусора предназначен для того, чтобы новые алгоритмы GC были оценены с точки зрения их влияния на производительность. Идея состоит в том, чтобы запустить пример приложения с Epsilon и сгенерировать набор показателей. Включается новый алгоритм сборки мусора, запускаются те же тесты, а затем результаты сравниваются.
- Для очень коротких задач (считайте безсерверные функции в облаке), где вы можете гарантировать, что не превысите память, выделенную куче. Это может повысить производительность за счет отсутствия накладных расходов (включая сбор статистики, необходимой для принятия решения о запуске коллектора) в коде приложения. Если пространство кучи исчерпано, JVM может быть сконфигурирован с ошибкой одним из трех способов:
- Вызывается обычный
OutOfMemoryError
. - Выполнить сброс кучи
- Сбой жесткого диска JVM и, возможно, выполнение другой задачи (например, запуск отладчика).
- Вызывается обычный
- Предоставляет API для производства и потребления данных как событий
- Предоставляет буферный механизм и формат двоичных данных
- Разрешает настройку и фильтрацию событий
- Предоставлять события для ОС, JVM HotSpot и библиотек JDK
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ