JavaRush /Java блог /Java Developer /Java 13: новые возможности

Java 13: новые возможности

Статья из группы Java Developer
Мы уже успели привыкнуть к тому, что новый релиз JDK появляется раз в полгода. Пока что такой подход себя оправдал, а переживания некоторых разработчиков, дескать они не будут поспевать за обновлениями, оказались напрасными: полугодовых изменений немного и они не столь глобальны, как раньше. Ну а начинающие программисты могут и вовсе не заметить новшества. Java 13: новые возможности - 1Тем не менее, будущим разработчикам ПО лучше быть в курсе нововведений. В этой статье мы традиционно опишем принятые предложения по расширению (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.
Любопытно, что эти методы только появились, но уже помечены как deprecated... такое положение вещей наводит на мысль, что их могут удалить в будущей версии JDK. Это кажется несколько эксцентричным — добавлять новый метод и сразу же отказываться от него. Однако нужно учесть, что эти методы связаны с превью-фичей, которая может быть изменена или удалена. Возможно, введение аннотации @PreviewFeature помогло бы с подобными ситуациями, но пока такая она не входит в JDK (хотя с высокой долей вероятности она появится в JDK 14).

JEP 354: Switch Expression (Preview)

В Java 12 появилось предложение о новой форме написания выражений с оператором switch — JEP 325. Оно оказалось самой первой превью-фичей и её судьба доказывает, что выносить предложения на суд пользователей — отличная идея. До JDK 12 switch можно было использовать только как оператор, который выполняет действие, но не возвращает результат. А вот в 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 также позволяет использовать breakcontinue) с меткой наподобие оператора безусловного перехода 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

Обе реализации API java.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 получают три новых метода для создания экземпляров, поддерживающих пространство имен.
Материал основан на статье Саймона Риттера и официальной документации.
Комментарии (9)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Fuhrer_51[RUS] Уровень 1
30 октября 2019
Народ . . . Вот я пока ни черта не шарю, поэтому, возможно сейчас будет какой-то ну совсем тупой вопрос. Собственно, по этой же причине будет много текста для точности, дабы избежать неточностей в понимании. Не так давно вообще начал интересоваться этой темой, читать всякое. И тут решил было начать чему-то обучаться по книге одной: "Библиотека профессионала Java" в двух томах. Хей Хорстманн и Гари Корнелл. Если это важно — девятое издание, 2014г. И первое на чём я начал спотыкаться, это этап подготовки всего и вся. Вроде скачал что надо, вроде бы установил, был пункт о Задании пути к исполняемым файлам, но, как я понял из процесса, делать тут ничего не нужно было, поскольку в пункте path (Система/Дополнительные параметры системы/Дополнительно/Переменные среды/Системные переменные) уже были указанные моменты, что подтвердил тест из книги, в виде команды "java -version" в cmd. Ну а далее пункт Установки библиотек. В процессе нужно было создать папку src и разархивировать некий src.zip в эту папку. Всё это, по рекомендации авторов, должно делаться всё так же в cmd (окей, мне не трудно, тут я хоть что-то умею :D). Однако в той очерёдности, что там указана, ничего не выходит. Да и сам архив я вообще нашёл в другой папке, где-то в [диск]\[другие папки]\Java DE\lib. Книга всё время описывает JDK1,7 (вообще не плаваю в версиях и прочем этом деле), а тут уже, как я понял, 13я вышла. 😵 Хотя по той же команде проверки версии говорится 1.8, но это уже другой вопрос на тему что вообще означает цифра эта и что есть 13... Собственно, решил спросить тут, вдруг вообще процесс этот устарел за 5 лет и всё это вовсе не актуально, что будет вполне логично. Ввиду слабых отсутствия знаний по этой теме я как-то не сформировал адекватного запроса для гугла :D А меня всё время кидало на девлоги версий, да и все на инглише. 😖 Да-да-да, я с ним слабо знаком, если это вообще можно именовать знакомством. :\
Natallia Уровень 5
23 октября 2019
тем временем, большая часть кремниевой долины до сих пор сидит на 8м и в ус не дует=)
Munoon Уровень 41
24 сентября 2019
Хорошая статья, но скучное обновление(
Dmitrii Уровень 20
19 сентября 2019
Спасибо)
Алексей Уровень 22
19 сентября 2019
вай спасибо за статью, Эллеонорчик джан!😊