Мы уже успели привыкнуть к тому, что новый релиз JDK появляется раз в полгода. Пока что такой подход себя оправдал, а переживания некоторых разработчиков, дескать они не будут поспевать за обновлениями, оказались напрасными: полугодовых изменений немного и они не столь глобальны, как раньше. Ну а начинающие программисты могут и вовсе не заметить новшества.
Тем не менее, будущим разработчикам ПО лучше быть в курсе нововведений. В этой статье мы традиционно опишем принятые предложения по расширению (JEP). Java 13 включает в себя только пять JEP’ов и 76 новых элементов базовой библиотеки (из которых почти половина — простые дополнения к пакету java.io).

JEP 355: Text Blocks(Preview)
Начнем с изменения синтаксиса языка. Самое значительное из них — это текстовые блоки. Они позволяют избегать экранирования символов и умеют форматировать строки. Возможно, вы помните, что в JDK 12 так и не появилась ожидаемая фича Raw String Literals (JEP 326) для работы со строковыми литералами. В Java 13 ей на смену пришёл JEP 355 с его текстовыми блоками. Вы, вероятнее всего, помните, что в Java строка обёрнута в двойные кавычки. Это хорошо, но проблема в том, что строка не может занимать больше одной линии исходного файла (чтобы не путать с Java-строкой, здесь будем называть строку файла “линией”). Что ж, пойдём в обход и используем, например, символ\n
, если требуется разрыв, или конкатенацию многострочных выражений. Не очень-то красиво получается! Особенно громоздко выглядят текстовые литералы со встроенными фрагментами HTML, XML, SQL или JSON. Все эти экранирования, конкатенации, ручное редактирование делает код неудобным для написания и трудночитаемым.
Текстовые блоки пытаются эту проблему решить. Они начинаются эээ… с тройных двойных кавычек и заканчиваются ими же (знаю, звучит не очень). Всё, что находится между кавычками, интерпретируется как часть строки, включая переводы на новую линию. Текстовые блоки можно использовать точно так же, как стандартные текстовые литералы, Java скомпилирует код одинаково.
Открывающие кавычки должны сопровождаться ограничителем строки; текстовые блоки нельзя использовать в одну линию, так что код
String smallBlock = """Only one line""";
приведёт к следующим ошибкам:
TextBlock.java:3: error: illegal text block open delimiter sequence, missing line terminator
String smallBlock = """Text Block""";
^
TextBlock.java:3: error: illegal text block open delimiter sequence, missing line terminator
String smallBlock = """Text Block""";
^
Простой HTML-фрагмент теперь можно написать так:
String htmlBlock = """
<html>
<body>
<p>CodeGym Web page</p>
</body>
<html>
""";
Упомянём несколько тонкостей, о которых лучше знать при использовании текстовых блоков. Расположение закрывающих кавычек оказывается важным: оно определяет, как обрабатывается случайный пробел. В приведенном выше примере закрывающие кавычки выровнены с отступом текста HTML. В этом случае компилятор удалит пробелы отступа, и в результате мы получим такую строку:
<html>
<body>
<p>My web page</p>
</body>
</html>
Обратите внимание: такая строка будет содержать новую линию в конце строки. Если она не нужна, закрывающие кавычки “”” можно поставить непосредственно после тега </ html>.
Если мы переместим закрывающие кавычки ближе к левому полю, это изменит количество удаленных отступов. Если бы мы переместили их на два пробела влево, мы бы добавили два пробела для отступа к каждой линии строки. Перемещение к левому краю приведет к тому, что все отступы будут сохранены. Перемещение кавычек дальше вправо не возымеет никакого эффекта и не добавит больше отступов.
В версию JDK 13 текстовые блоки попали в качестве превью-фичи. Это значит, что они пока не включены в соответствующую спецификацию языка Java. То есть непонятно, станет ли эта фича постоянной частью языка или она тут только гость. В настоящее время разработчики могут протестировать фичу и высказать мнение о ней. От него и будет зависеть судьба текстовых блоков: фичу могут улучшить, а если она не понравится — то и вовсе удалить. Если вы хотите опробовать текстовые блоки на практике, помните, что превью-фичи нужно явно включать для компиляции и выполнения.
Компиляция:
javac --enable-preview --release 13 TextBlock.java
Чтобы запустить приложение, нужно включить функции предварительного просмотра:
java --enable-preview TextBlock
В классе String
есть три новых метода, которые дополняют это изменение языка:
formatted()
: форматирует строку, используя саму строку в качестве строки формата. Эквивалентен вызовуformat(this, args)
stripIndent()
: удаляет случайные пробелы из строки. Это полезно, если вы читаете многострочные строки и хотите применить такое же исключение случайных пробелов, как и в случае явного объявления.translateEscapes()
: возвращает строку с escape-последовательностями (например,\ r
), переведенными в соответствующее значение Unicode.
@PreviewFeature
помогло бы с подобными ситуациями, но пока такая она не входит в JDK (хотя с высокой долей вероятности она появится в JDK 14).
JEP 354: Switch Expression (Preview)
В Java 12 появилось предложение о новой форме написания выражений с оператором switch — JEP 325. Оно оказалось самой первой превью-фичей и её судьба доказывает, что выносить предложения на суд пользователей — отличная идея. До JDK 12switch
можно было использовать только как оператор, который выполняет действие, но не возвращает результат. А вот в Java 12 позволила использовать switch
как выражение, возвращающее результат, который можно присвоить переменной. Были и другие изменения, в синтаксисе операторов case внутри switch
. Давайте рассмотрим пример из JEP, чтобы разобраться, как это работает.
int numberOfLetters;
switch(dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numberOfLetter = 6;
break;
case TUESDAY
numberOfLetter = 7;
break;
case THURSDAY
case SATURDAY
numberOfLetter = 8;
break;
case WEDNESDAY
numberOfLetter = 9;
break;
default:
throw new IllegalStateException("Huh?: " + day);
}
В этом примере мы используем значение dayOfWeek
, чтобы присвоить значение numberOfLetters
. Из-за особенностей работы оператора switch
, данный код — не самый красивый и в нём легко наделать ошибок. Во-первых, если мы забудем применить оператор break
для каждой группы case-меток, мы по умолчанию перейдём к следующей группе меток. Это может привести к ошибкам, которые сложно отыскать. Во-вторых, мы должны определить каждую группу case-меток. Если забудем, то, разумеется, получим ошибку компилятора, однако и такой вариант не идеален. Также наш код весьма многословен, поскольку каждое значение dayOfWeek
должно иметь свою собственную case-метку.
Используя новый синтаксис, мы получаем намного более чистый и менее подверженный ошибкам код:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> throw new IllegalStateException("Huh?: " + day);
};
Теперь нам нужно сделать присваивание только один раз (из возвращаемого выражением switch
значения) и можно использовать разделяемый запятыми список для case-меток. И, поскольку мы не используем оператор break
, то устраняем связанные с ним проблемы.
Синтаксис выражения switch
позволяет использовать синтаксис более старого стиля, поэтому в JDK 12 мы можем написать и так:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
break 6;
case TUESDAY
break 7;
case THURSDAY
case SATURDAY
break 8;
case WEDNESDAY
break 9;
default:
throw new IllegalStateException("Huh?: " + day);
};
Согласно мнению Java-сообщества, перегрузка использования break
для указания возвращаемого значения может сбивать с толку. Язык Java также позволяет использовать break
(и continue
) с меткой наподобие оператора безусловного перехода goto
. В JEP 354 было изменено подобное использование break
, так что в Java 13 наш код несколько меняется:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
yield 6;
case TUESDAY
yield 7;
case THURSDAY
case SATURDAY
yield 8;
case WEDNESDAY
yield 9;
default:
throw new IllegalStateException("Huh?: " + day);
};
Следующие три JEP’а связаны с виртуальной машиной Java.
JEP 350 Dynamic CDS Archive
Это расширение позволяет провести динамическое архивирование классов в конце выполнения Java-приложения. CDS или Class Data Sharing позволяет упаковать все запускаемые при старте классы в специальный архивclass data sharing
, используя список этих самых классов по умолчанию. Это приводит к существенному ускорению запуска приложений и экономии оперативной памяти.
Раньше использование AppCDS было многоэтапным процессом, включающим создание списка соответствующих классов и использование этого списка для создания архива, который будет использоваться для последующих запусков. Теперь всё, что требуется, — это один запуск приложения с флагом -XX: ArchiveClassesAtExit
, указывающим место, куда будет записан архив. При таком подходе классы автоматически упаковываются в архив после нормальной остановки приложения.
JEP 351 ZGC: Uncommit unused memory
Год назад в JDK 11 быд представлен ZGC — экспериментальный масштабируемый сборщик мусора с низкой задержкой. Поначалу ZGC вёл себя довольно странно: он не позволял вернуть память операционной системе, даже если она уже была не нужна. Для некоторых сред, например, для контейнеров, где ресурсы используются несколькими службами одновременно, это может ограничивать масштабируемость и эффективность системы. Куча ZGC состоит из так называемых ZPages. Когда ZPages очищаются во время цикла сбора мусора, они возвращаются в кэш ZPageCache. ZPages в этом кэше упорядочены по порядку давности использования. В Java 13 ZGC будет возвращать в операционную систему страницы, которые были определены как те, что не использовались достаточно долго. Таким образом их можно будет использовать повторно для других процессов.JEP 353 Reimplement the legacy Socket API
Обе реализации APIjava.net.Socket
и java.net.ServerSocket
относятся ещё JDK 1.0. В этой, да и во всех последующих JDK, реализация этих API-интерфейсов использует несколько методов (таких, как использование стека потоков в качестве буфера ввода-вывода), которые делают их негибкими и сложными в обслуживании.
Чтобы решить эту проблему, в JDK 13 предоставили новую реализацию NioSocketImpl
. Она больше не требует нативного кода, тем самым упрощая портирование на разные платформы. Этот класс также использует существующий механизм буферного кэша (исключая использование стека потоков для этой цели) и блокировки java.util.concurrent
, а не синхронизированные методы. Это упростит интеграцию с файберами из Project Loom.
Новые API
Мы уже упоминали ранее, что Java 13 включает в себя 76 новых API в библиотеках базовых классов. Они охватывают следующие области:- Обновления поддержки Unicode.
- Три новых метода в
String
для поддержки текстовых блоков (см. описание JEP 255 выше). - Классы
java.nio
теперь имеют абсолютные (в отличие от относительных)get
иset-методы. Они, как и базовый абстрактный класс Buffer
, включают методslice()
для извлечения части буфера. - Метод
force()
классаMappedByteBuffer
принудительно записывает раздел буфера в его резервное хранилище. nio.FileSystem
добавляет три новые перегруженные формыnewFileSystem()
для доступа к содержимому файла как файловой системы.- В
javax.annotation.processing.ProcessingEnvironment
появился новый интересный метод.isPreviewEnabled()
. Он сообщит о том, включены ли preview-фичи. Это интересно потому, что упомянутая выше аннотация@PreviewFeature
не будет доступна до выхода JDK 14. DocumentBuilderFactory
иSAXParserFactory
вjavax.xml.parsers
получают три новых метода для создания экземпляров, поддерживающих пространство имен.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
отсутствиязнаний по этой теме я как-то не сформировал адекватного запроса для гугла :D А меня всё время кидало на девлоги версий, да и все на инглише. 😖 Да-да-да, я с ним слабо знаком, если это вообще можно именовать знакомством. :\