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

Новые возможности в Java 9

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

1. Обзор

Java 9 поставляется с богатым набором функций. Хотя новых языковых концепций нет, новые API и диагностические команды определенно будут интересны разработчикам.

В этом обзоре мы кратко рассмотрим некоторые новые функции; полный список новых функций доступен здесь .

2. Модульная система — Проект Jigsaw

Давайте начнем с большого — внедрения модульности в платформу Java.

Модульная система предоставляет возможности, аналогичные системе платформы OSGi. Модули имеют концепцию зависимостей, могут экспортировать общедоступный API и сохранять детали реализации скрытыми/приватными.

Одним из основных мотивов здесь является предоставление модульной JVM, которая может работать на устройствах с гораздо меньшим объемом доступной памяти. JVM может работать только с теми модулями и API, которые требуются приложению. По этой ссылке вы найдете описание этих модулей.

Кроме того, внутренние API-интерфейсы JVM (реализации), такие как com.sun.* , больше недоступны из кода приложения.

Проще говоря, модули будут описаны в файле с именем module-info.java, расположенном в верхней части иерархии кода Java:

module com.foreach.java9.modules.car {
requires com.foreach.java9.modules.engines;
exports com.foreach.java9.modules.car.handling;
}

Наш модуль car требует запуска модуля модуля и экспортирует пакет для обработки .

Более подробный пример см. в OpenJDK Project Jigsaw: Module System Quick-Start Guide .

3. Новый HTTP-клиент

Долгожданная замена старому HttpURLConnection .

Новый API находится в пакете java.net.http .

Он должен поддерживать как протокол HTTP/2, так и рукопожатие WebSocket с производительностью, сравнимой с Apache HttpClient , Netty и Jetty .

Давайте посмотрим на эту новую функциональность, создав и отправив простой HTTP-запрос.

Обновление: HTTP-клиент JEP перемещается в модуль инкубатора, поэтому он больше не доступен в пакете java.net.http и вместо этого доступен в jdk.incubator.http.

3.1. Быстрый запрос GET

API использует шаблон Builder, что делает его очень простым для быстрого использования:

HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://postman-echo.com/get"))
.GET()
.build();

HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandler.asString());

4. Процесс API

API процесса был улучшен для контроля и управления процессами операционной системы.

4.1. Обрабатывать информацию

Класс java.lang.ProcessHandle содержит большинство новых функций:

ProcessHandle self = ProcessHandle.current();
long PID = self.getPid();
ProcessHandle.Info procInfo = self.info();

Optional<String[]> args = procInfo.arguments();
Optional<String> cmd = procInfo.commandLine();
Optional<Instant> startTime = procInfo.startInstant();
Optional<Duration> cpuUsage = procInfo.totalCpuDuration();

Текущий метод возвращает объект, представляющий процесс запущенной в данный момент JVM . Подкласс Info предоставляет подробную информацию о процессе.

4.2. Уничтожение процессов

Теперь давайте остановим все запущенные дочерние процессы с помощью destroy() :

childProc = ProcessHandle.current().children();
childProc.forEach(procHandle -> {
assertTrue("Could not kill process " + procHandle.getPid(), procHandle.destroy());
});

5. Небольшие языковые модификации

5.1. Попробуйте с ресурсами

В Java 7 синтаксис try-with-resources требует объявления новой переменной для каждого ресурса, управляемого оператором.

В Java 9 есть дополнительное уточнение: если на ресурс ссылается конечная или фактически конечная переменная, оператор try-with-resources может управлять ресурсом без объявления новой переменной:

MyAutoCloseable mac = new MyAutoCloseable();
try (mac) {
// do some stuff with mac
}

try (new MyAutoCloseable() { }.finalWrapper.finalCloseable) {
// do some stuff with finalCloseable
} catch (Exception ex) { }

5.2. Расширение оператора Diamond

Теперь мы можем использовать оператор алмаза в сочетании с анонимными внутренними классами:

FooClass<Integer> fc = new FooClass<>(1) { // anonymous inner class
};

FooClass<? extends Integer> fc0 = new FooClass<>(1) {
// anonymous inner class
};

FooClass<?> fc1 = new FooClass<>(1) { // anonymous inner class
};

5.3. Частный метод интерфейса

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

interface InterfaceWithPrivateMethods {

private static String staticPrivate() {
return "static private";
}

private String instancePrivate() {
return "instance private";
}

default void check() {
String result = staticPrivate();
InterfaceWithPrivateMethods pvt = new InterfaceWithPrivateMethods() {
// anonymous class
};
result = pvt.instancePrivate();
}
}}

6. Инструмент командной строки JShell

JShell — это цикл чтения-оценки-печати — REPL для краткости.

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

Сам исполняемый файл jshell можно найти в папке <JAVA_HOME>/bin :

jdk-9\bin>jshell.exe
| Welcome to JShell -- Version 9
| For an introduction type: /help intro
jshell> "This is my long string. I want a part of it".substring(8,19);
$5 ==> "my long string"

Интерактивная оболочка поставляется с историей и автозаполнением; он также предоставляет функциональные возможности, такие как сохранение и загрузка из файлов всех или некоторых письменных операторов:

jshell> /save c:\develop\JShell_hello_world.txt
jshell> /open c:\develop\JShell_hello_world.txt
Hello JShell!

Фрагменты кода выполняются при загрузке файла.

7. Подкоманды JCMD

Давайте рассмотрим некоторые новые подкоманды в утилите командной строки jcmd . Мы получим список всех классов, загруженных в JVM, и их структуру наследования.

В приведенном ниже примере мы видим иерархию java.lang.Socket , загруженную в JVM, на которой работает Eclipse Neon:

jdk-9\bin>jcmd 14056 VM.class_hierarchy -i -s java.net.Socket
14056:
java.lang.Object/null
|--java.net.Socket/null
| implements java.io.Closeable/null (declared intf)
| implements java.lang.AutoCloseable/null (inherited intf)
| |--org.eclipse.ecf.internal.provider.filetransfer.httpclient4.CloseMonitoringSocket
| | implements java.lang.AutoCloseable/null (inherited intf)
| | implements java.io.Closeable/null (inherited intf)
| |--javax.net.ssl.SSLSocket/null
| | implements java.lang.AutoCloseable/null (inherited intf)
| | implements java.io.Closeable/null (inherited intf)

Первый параметр команды jcmd — это идентификатор процесса (PID) JVM, на которой мы хотим запустить команду.

Еще одна интересная подкоманда — set_vmflag . Мы можем изменить некоторые параметры JVM онлайн, без необходимости перезапуска процесса JVM и изменения его параметров запуска.

Узнать все доступные флаги ВМ можно с помощью подкоманды jcmd 14056 VM.flags -all

8. API изображений с несколькими разрешениями

Интерфейс java.awt.image.MultiResolutionImage инкапсулирует набор изображений с разным разрешением в один объект. Мы можем получить вариант изображения для конкретного разрешения на основе заданной метрики DPI и набора преобразований изображения или получить все варианты изображения.

Класс java.awt.Graphics получает вариант изображения с несколькими разрешениями на основе текущей метрики DPI дисплея и любых примененных преобразований.

Класс java.awt.image.BaseMultiResolutionImage обеспечивает базовую реализацию:

BufferedImage[] resolutionVariants = ....
MultiResolutionImage bmrImage
= new BaseMultiResolutionImage(baseIndex, resolutionVariants);
Image testRVImage = bmrImage.getResolutionVariant(16, 16);
assertSame("Images should be the same", testRVImage, resolutionVariants[3]);

9. Переменные дескрипторы

API находится в java.lang.invoke и состоит из VarHandle и MethodHandles . Он предоставляет эквиваленты операций java.util.concurrent.atomic и sun.misc.Unsafe для полей объекта и элементов массива с аналогичной производительностью.

В модульной системе Java 9 доступ к sun.misc.Unsafe из кода приложения будет невозможен.

10. Платформа публикации-подписки

Класс java.util.concurrent.Flow предоставляет интерфейсы, поддерживающие платформу публикации-подписки Reactive Streams . Эти интерфейсы поддерживают взаимодействие между несколькими асинхронными системами, работающими на JVM.

Мы можем использовать служебный класс SubmissionPublisher для создания пользовательских компонентов.

11. Унифицированное ведение журнала JVM

Эта функция вводит общую систему ведения журналов для всех компонентов JVM. Он предоставляет инфраструктуру для ведения журналов, но не добавляет фактические вызовы журналов из всех компонентов JVM. Он также не добавляет журналирование в код Java в JDK.

Фреймворк ведения журнала определяет набор тегов — например, gc , компилятор , потоки и т. д . Мы можем использовать параметр командной строки -Xlog , чтобы включить ведение журнала во время запуска.

Давайте запишем сообщения, помеченные тегом «gc», используя уровень «debug» в файл с именем «gc.txt» без каких-либо украшений:

java -Xlog:gc=debug:file=gc.txt:none ...

-Xlog:help выведет возможные варианты и примеры. Конфигурация ведения журнала может быть изменена во время выполнения с помощью команды jcmd . Мы собираемся установить журналы GC в информацию и перенаправить их в файл — gc_logs:

jcmd 9615 VM.log output=gc_logs what=gc

12. Новые API

12.1. Неизменяемый набор

java.util.Set.of() — создает неизменяемый набор заданных элементов. В Java 8 для создания набора из нескольких элементов потребовалось бы несколько строк кода. Теперь мы можем сделать это так же просто, как:

Set<String> strKeySet = Set.of("key1", "key2", "key3");

Набор , возвращаемый этим методом, является внутренним классом JVM: java.util.ImmutableCollections.SetN , который расширяет общедоступный java.util.AbstractSet . Он неизменен — если мы попытаемся добавить или удалить элементы, будет выброшено исключение UnsupportedOperationException .

Вы также можете преобразовать весь массив в набор тем же методом.

12.2. Необязательно для потоковой передачи

java.util.Optional.stream() дает нам простой способ использовать возможности потоков для необязательных элементов:

List<String> filteredList = listOfOptionals.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());

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

Java 9 будет поставляться с модульной JVM и множеством других новых и разнообразных улучшений и функций.

Вы можете найти исходный код примеров на GitHub .