Нововведения в Java 9: разбираем на примерах

Ожидается, что новая версия Java 9 выйдет уже 27 июля 2017 года. Давайте разберёмся, какие функции появятся, и расскажем, зачем они нужны.

Вот список важных нововведений Java 9:

  1. JShell;
  2. Immutable List, Set и Map из коробки;
  3. Private методы в интерфейсах;
  4. Модульная система;
  5. Улучшение API;
  6. Изменения в try-with-resources;
  7. Реактивное программирование;
  8. Diamond оператор для анонимных классов;
  9. Дополнительные улучшения в классах;
  10. Улучшения Stream API;
  11. Расширенные аннотации @Deprecated;
  12. HTTP/2 клиент;
  13. API отзывчивых изображений;
  14. Разное.

С помощью примеров расскажем подробнее об этих функциях.

JShell

REPL (англ. read-eval-print loop) — система для интерактивного программирования в консоли. То есть если пользователь вводит строку кода, в консоли появляется результат её выполнения и этот процесс повторяется.

Oracle представила новый инструмент под названием «JShell». Он используется для тестирования и использования в консоли разных конструкций, например классов, интерфейсов, перечислений, объектов, операторов и т.д.

Кстати, уже сейчас можно загрузить бета-версию JDK 9, скачав её с официального сайта.

Простейший пример работы с JShell:

G:\>jshell
|  Welcome to JShell -- Version 9-ea
|  For an introduction type: /help intro
 

jshell> int a = 10
 a ==> 10

jshell> System.out.println("a value = " + a)
 a value = 10

Неизменяемые объекты List, Set и Map «из коробки»

Oracle представила несколько удобных методов для создания неизменяемых List, Set, Map и Map.Entry объектов без использования дополнительных классов

В Java SE 8 и более ранних версиях мы можем использовать Collections.unmodifiableXXX для создания неизменяемых объектов коллекций. К примеру, если мы хотим создать Immutable List, мы будем использовать Collections.unmodifiableList метод.

Однако это неудобно, поэтому Oracle добавила несколько вспомогательных методов в интерфейсы List, Set и Map.

List и Set интерфейсы имеют of() методы. Примеры их использования можно увидеть ниже:

List immutableList = List.of();  // пустой неизменяемый список

List immutableList = List.of("one","two","three");  // неизменяемый список, содержащий информацию

Map имеет два набора методов: of() методы и ofEntries() методы для создания объектов Immutable Map и Map.Entry.

jshell> Map emptyImmutableMap = Map.of()	
 emptyImmutableMap ==> {}  // пустое неизменяемое отображение

jshell> Map nonemptyImmutableMap = Map.of(1, "one", 2, "two", 3, "three")
 nonemptyImmutableMap ==> {2=two, 3=three, 1=one}  // неизменяемое отображение

Private методы в интерфейсах

В Java 8 мы можем обеспечивать реализацию метода в интерфейсах, используя default и static методы. Однако мы не можем создавать private методы в интерфейсах.
Для избавления от нагромождения и переизбытка кода Oracle собирается добавить private методы в интерфейсы Java SE 9. Начиная с девятой версии, мы также сможем создавать private static методы в интерфейсах с помощью private.

Создание реализации метода для интерфейса по умолчанию:

public interface Card
{

    private Long createCardID()
    {
        // Реализация метода происходит здесь.
    }

    private static void displayCardDetails()
    {
        // Реализация метода происходит здесь.
    }

}

Модульная система

Одним из самых значительных изменений является появление модульной системы. До Java 9 мы использовали JAR-файлы для разработки приложений, базирующихся на Java. Однако, эта архитектура имеет несколько ограничений и недостатков. Для их устранения и внедрили модульную систему. Это нововведение является частью проекта Jigsaw, который разрабатывается для того, чтобы программисты могли разбивать программы на независимые и межпрограммные модули. 

Вот некоторые из функций этой системы:

  • модульная JDK;
  • модульный исходный код Java;
  • модульные run-time изображения;
  • инкапсуляция внутренних API;
  • система модульной платформы;

JDK 9 поставляется с 92 модулями. Мы можем использовать их или создать свои, например:

module com.foo.bar { }

Каждый модуль имеет имя, связанный код и другие ресурсы.

Улучшение API

Ожидается, что в Java SE 9 будут произведены улучшения по части API. Будут добавлены несколько новых классов и методов для более удобного управления действиями операционной системы.
Два новых интерфейса в Process API:

  • java.lang.ProcessHandle;
  • java.lang.ProcessHandle.Info.

Пример Process API:

ProcessHandle currentProcess = ProcessHandle.current();

System.out.println("Current Process Id: = " + currentProcess.getPid());

Здесь нами был создан объект типа ProcessHandle для работы с действиями операционной системе.

Изменения в try-with-resources

Как мы знаем, в Java SE 7 появилась новая конструкция обработки исключений Try-With-Resources для автоматического управления ресурсами. В Java SE 9 собираются внести несколько изменений в эту конструкцию, чтобы повысить читаемость.
Пример в Java SE 7:

void testARM_Before_Java9() throws IOException
{
    BufferedReader reader1 = new BufferedReader(new FileReader("journaldev.txt"));

        try (BufferedReader reader2 = reader1) {
            System.out.println(reader2.readLine());
        }
     
}

Пример в Java 9:

void testARM_Java9() throws IOException
{
    BufferedReader reader1 = new BufferedReader(new FileReader("journaldev.txt"));

        try (reader1) {
            System.out.println(reader1.readLine());
        }

}

Можно заметить, что в новой версии, после try не обязательно объявлять новую переменную.

Новшества в CompletableFuture API

В Java 9 Oracle также собирается улучшить CompletableFuture API для решения проблем, появившихся в Java SE 8. В планах добавить задержки и тайм-ауты, дополнительные методы и улучшить подклассы.

Пример:

Executor exe = CompletableFuture.delayedExecutor(50L, TimeUnit.SECONDS);

Здесь delayedExecutor() — static метод, используемый для возврата исполнителя, после заданной задержки.

Реактивное программирование

Для тех, кто ещё не знаком с парадигмой реактивного программирования, советуем прочитать наше введение в тему с примерами.
В Scala, Play, Akka уже были интегрированы reactive streams. Oracle решила добавить Reactive Streams API в Java SE 9.

Java SE 9 Reactive Streams API — фреймворк для реализации асинхронных, масштабируемых и параллельных приложений с использованием Java.

В Java SE 9 появятся следующие API:

  • java.util.concurrent.Flow;
  • java.util.concurrent.Flow.Publisher;
  • java.util.concurrent.Flow.Subscriber;
  • java.util.concurrent.Flow.Processor.

Diamond оператор для анонимных классов

Предположим, что у нас есть класс Box<T> и мы хотим сделать его анонимным.
Вот как выглядит этот процесс в Java 8:

<T> Box<T> createBox(T content)
{
    // Нужно поставить 'T' здесь 🙁
    return new Box<T>(content) { };
}

Разве не очевидно, что Box должен быть типа T? Компилятор в случае не-анонимного класса выбрал бы нужный тип, так почему бы не сделать то же самое с анонимным?

Проблема в не обозначаемых (англ. non-denotable) типах, которые распознаются компилятором, а JVM — нет. (Такой случай может быть обработан компилятором, но вопрос — как корректно передать его JVM.)

Поэтому Diamond оператор не допускался в использовании с анонимными классами. Теперь же это возможно.

Вот как это выглядит в Java 9:

class inJava
{

        <T> Box<T> createBox(T content)
    {
        // Java 9 выводит ‘T’, потому что этот тип обозначаемый
        return new Box<>(content) { };
    }

    Box<?> createCrazyBox(Object content)
    {
        List <?> innerList = Arrays.asList(content);
        // А этот тип не выводится, так как не можем его обозначить:
        // return new Box<>(innerList) { };
        // Вместо этого обозначаем тот тип, который нам нужен:
        return new Box<List<?>>(innerList) { };
    }

}

Дополнительные улучшения в классах

В Java SE 9 Oracle добавила несколько полезных методов в java.util.Optional.
Вот например как работает метод stream:

Stream<Optional> emp = getEmployee(id);

Stream empStream = emp.flatMap(Optional::stream);

Здесь используется метод Optional.stream(), который конвертирует всё в поток Employee.

Улучшения Stream API

В новой версии появятся как минимум четыре метода java.util.Stream. Как и stream, все они будут стандартными. Наиболее важными являются dropWhile и takeWhile методы.
Если вы знакомы с языком Scala или функциональным программированием, вы обязательно узнаете эти методы.

Простейшее применение stream:

jshell> Stream.of(1,2,3,4,5,6,7,8,9,10).takeWhile(i -> i < 5 ).forEach(System.out::println);

Расширенные аннотации @Deprecated

До Java 9 @Deprecated — просто интерфейс-маркер. Многие разработчики предлагали Oracle улучшить информирование об устаревших возможностях API. Их услышали и добавили возможности работы с устаревшими API. Например, появились инструменты для их анализа — forRemoval и since.

HTTP/2 клиент

Oracle планирует выкатить новый HTTP-клиент для поддержки протоколов HTTP/2 и WebSocket. Они заменяют HttpURLConnection API на новый, более производительный.
Новый API будет представлен в пакете «java.net.http». Он поддерживает как синхронный, так и асинхронный режимы.

Новый API можно посмотреть на официальном сайте Oracle в разделе документаций.
Пример HTTP/2 Client:

jshell> import java.net.http.*

jshell> import static java.net.http.HttpRequest.*

jshell> import static java.net.http.HttpResponse.*

jshell> URI uri = new URI("http://rams4java.blogspot.co.uk/2016/05/java-news.html")
 uri ==> http://rams4java.blogspot.co.uk/2016/05/java-news.html

jshell> HttpResponse response = HttpRequest.create(uri).body(noBody()).GET().response()
 response ==> java.net.http.HttpResponseImpl@79efed2d

jshell> System.out.println("Response was " + response.body(asString()))

API для изображений с разными разрешениями

Oracle планирует внедрить новый API для изображений разных разрешений. Наиболее важным является интерфейс MultiResolutionImage доступный в пакете  java.awt.image.

Другие изменения

Помимо вышеперечисленных изменений, ожидаются и другие. Вот лишь некоторые из них:

  1. Изменения в Garbage Collector;
  2. Изменения в API Stack-Walking;
  3. Фильтр входящих данных сериализации;
  4. Отключение API апплета;
  5. Изменения конкатенации строк;
  6. Улучшения в MethodHandle;
  7. Логирование;
  8. Парсер API для Nashorn;
  9. Поиск по JavaDoc;
  10. HTML5 JavaDoc.

Перевод статьи «Java 9 Features with Examples»