Перейти к основному содержимому

Новые функции в Java 13

· 6 мин. чтения

1. Обзор

В сентябре 2019 года был выпущен JDK 13 в соответствии с новой периодичностью выпуска Java в шесть месяцев . В этой статье мы рассмотрим новые функции и улучшения, представленные в этой версии.

2. Предварительный просмотр функций разработчика

Java 13 привнесла две новые языковые функции, хотя и в режиме предварительного просмотра . Это означает, что эти функции полностью реализованы для оценки разработчиками, но не готовы к работе. Кроме того, их можно удалить или сделать постоянными в будущих выпусках на основе отзывов.

Нам нужно указать –enable-preview в качестве флага командной строки, чтобы использовать функции предварительного просмотра . Давайте рассмотрим их подробно.

2.1. Выражения переключения (JEP 354)

Изначально мы видели выражения switch в JDK 12 . Выражения переключения Java 13 `` основаны на предыдущей версии, добавляя новый оператор yield .

Используя yield , теперь мы можем эффективно возвращать значения из выражения switch :

@Test
@SuppressWarnings("preview")
public void whenSwitchingOnOperationSquareMe_thenWillReturnSquare() {
var me = 4;
var operation = "squareMe";
var result = switch (operation) {
case "doubleMe" -> {
yield me * 2;
}
case "squareMe" -> {
yield me * me;
}
default -> me;
};

assertEquals(16, result);
}

Как мы видим, теперь легко реализовать шаблон стратегии с помощью нового переключателя.

2.2. Текстовые блоки ( JEP 355 )

Вторая функция предварительного просмотра — это текстовые блоки для многострочных строк , таких как встроенные JSON, XML, HTML и т. д.

Раньше, чтобы встроить JSON в наш код, мы объявляли его как строковый литерал:

String JSON_STRING 
= "{\r\n" + "\"name\" : \"ForEach\",\r\n" + "\"website\" : \"https://www.%s.com/\"\r\n" + "}";

Теперь давайте напишем тот же JSON, используя текстовые блоки String :

String TEXT_BLOCK_JSON = """
{
"name" : "ForEach",
"website" : "https://www.%s.com/"
}
""";

Как видно, нет необходимости экранировать двойные кавычки или добавлять возврат каретки. Используя текстовые блоки, встроенный JSON намного проще писать, легче читать и поддерживать.

Более того, доступны все функции String :

@Test
public void whenTextBlocks_thenStringOperationsWorkSame() {
assertThat(TEXT_BLOCK_JSON.contains("ForEach")).isTrue();
assertThat(TEXT_BLOCK_JSON.indexOf("www")).isGreaterThan(0);
assertThat(TEXT_BLOCK_JSON.length()).isGreaterThan(0);
}

Кроме того, java.lang.String теперь имеет три новых метода для работы с текстовыми блоками:

  • stripIndent () — имитирует компилятор для удаления случайных пробелов
  • translateEscapes() — переводит escape-последовательности, такие как «\\t» , в «\t».
  • formatted() — работает так же, как String::format, но для текстовых блоков

Давайте быстро рассмотрим пример String::formatted :

assertThat(TEXT_BLOCK_JSON.formatted("foreach").contains("www.foreach.com")).isTrue();
assertThat(String.format(JSON_STRING,"foreach").contains("www.foreach.com")).isTrue();

Поскольку текстовые блоки являются функцией предварительного просмотра и могут быть удалены в будущем выпуске, эти новые методы помечены как устаревшие.

3. Динамические архивы CDS (JEP 350)

Совместное использование данных классов (CDS) уже некоторое время является заметной функцией Java HotSpot VM. Это позволяет совместно использовать метаданные классов между различными JVM, чтобы сократить время запуска и объем памяти . JDK 10 расширил эту возможность, добавив приложения CDS ( AppCDS ), чтобы дать разработчикам возможность включать классы приложений в общий архив. JDK 12 еще больше расширил эту функцию, включив архивы CDS по умолчанию .

Однако процесс архивирования классов приложений был утомительным. Чтобы создать архивные файлы, разработчикам приходилось выполнять пробные запуски своих приложений, чтобы сначала создать список классов, а затем сбросить его в архив. После этого этот архив можно было использовать для обмена метаданными между JVM.

Благодаря динамическому архивированию JDK 13 упростил этот процесс. Теперь мы можем создать общий архив во время выхода из приложения . Это устранило необходимость в пробных запусках.

Чтобы приложения могли создавать динамический общий архив поверх системного архива по умолчанию, нам нужно добавить параметр -XX:ArchiveClassesAtExit и указать имя архива в качестве аргумента:

java -XX:ArchiveClassesAtExit=<archive filename> -cp <app jar> AppName

Затем мы можем использовать только что созданный архив для запуска того же приложения с параметром -XX:SharedArchiveFile :

java -XX:SharedArchiveFile=<archive filename> -cp <app jar> AppName

4. ZGC: отменить неиспользуемую память (JEP 351)

Сборщик мусора Z был представлен в Java 11 как механизм сборки мусора с малой задержкой, так что время паузы GC никогда не превышало 10 мс. Однако, в отличие от других GC HotSpot VM, таких как G1 и Shenandoah, он не был оборудован для возврата неиспользуемой памяти кучи в операционную систему. Java 13 добавила эту возможность в ZGC.

Теперь мы получаем уменьшенный объем памяти наряду с улучшением производительности.

Начиная с Java 13, ZGC по умолчанию возвращает операционной системе незафиксированную память до тех пор, пока не будет достигнут указанный минимальный размер кучи. Если мы не хотим использовать эту функцию, мы можем вернуться к Java 11 следующим образом:

  • Используя опцию -XX:-ZUncommit, или
  • Установка равных минимального ( -Xms ) и максимального ( -Xmx ) размеров кучи

Кроме того, ZGC теперь имеет максимальный поддерживаемый размер кучи 16 ТБ. Ранее пределом было 4 ТБ.

5. Повторно реализовать устаревший API сокетов (JEP 353)

Мы видели API-интерфейсы Socket ( java.net.Socket и java.net.ServerSocket ) как неотъемлемую часть Java с момента ее появления. Однако за последние двадцать лет они ни разу не модернизировались. Написанные на устаревших Java и C, они были громоздкими и сложными в обслуживании.

Java 13 преодолела эту тенденцию и заменила базовую реализацию , чтобы привести API в соответствие с футуристическими потоками пользовательского режима. Вместо PlainSocketImpl интерфейс провайдера теперь указывает на NioSocketImpl . Эта недавно написанная реализация основана на той же внутренней инфраструктуре, что и java.nio .

Опять же, у нас есть способ вернуться к использованию PlainSocketImpl . Мы можем запустить JVM с системным свойством -Djdk.net.usePlainSocketImpl , установленным как true , чтобы использовать более старую реализацию. По умолчанию используется NioSocketImpl.

6. Прочие изменения

Помимо перечисленных выше JEP, Java 13 принесла нам еще несколько заметных изменений:

  • java.nio — добавлен метод FileSystems.newFileSystem(Path, Map<String, ?>)
  • java.time — добавлено новое официальное название японской эпохи
  • javax.crypto — поддержка MS Cryptography Next Generation (CNG)
  • javax.security — добавлено свойство jdk.sasl.disabledMechanisms для отключения механизмов SASL
  • javax.xml.crypto — введены новые строковые константы для представления URI Canonical XML 1.1.
  • javax.xml.parsers — добавлены новые методы для создания экземпляров фабрик DOM и SAX с поддержкой пространств имен.
  • Поддержка Unicode обновлена до версии 12.1.
  • Добавлена поддержка канонизации основного имени Kerberos и ссылок между областями.

Кроме того, предлагается удалить несколько API . К ним относятся три метода String , перечисленные выше, и API javax.security.cert .

Среди удалений — инструмент rmic и старые функции инструмента JavaDoc . Реализации SocketImpl до JDK 1.4 также больше не поддерживаются.

7. Заключение

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

Как обычно, исходный код доступен на GitHub .