Нововведения Java 17

Java 17 — LTS-релиз. Для перехода с Java 11 важны не только возможности, финализированные именно в 17, но и изменения языка, появившиеся в релизах 12–16 и уже ставшие стабильной частью платформы.

Sealed classes — финальная возможность Java 17

Sealed-тип ограничивает список прямых наследников:

sealed interface Result permits Success, Failure {}
 
record Success(String value) implements Result {}
record Failure(String message) implements Result {}

Разрешённый наследник должен быть final, sealed или non-sealed. Если типы находятся в unnamed module, они должны быть в одном package; в named module достаточно одного модуля.

Что уже доступно при переходе с 11

Records

record Point(int x, int y) {
    Point {
        if (x < 0 || y < 0) throw new IllegalArgumentException();
    }
}

Record — компактный класс для прозрачного носителя данных. Он получает accessors, constructor, equals, hashCode, toString, является final, но может реализовывать интерфейсы. Records стали финальной возможностью в 16, а не в 17.

Pattern matching for instanceof

if (value instanceof String text && !text.isBlank()) {
    use(text);
}

Отдельное приведение не нужно; область видимости pattern variable зависит от потока управления. Возможность финализирована в Java 16.

Switch expressions

int weight = switch (priority) {
    case LOW -> 1;
    case NORMAL -> 5;
    case HIGH -> 10;
};

Несколько инструкций оформляются блоком с yield. Это финальная возможность Java 14. Pattern matching для switch в Java 17 был только preview и требовал флагов; стабильный вариант более поздних Java отличается, поэтому такой код нельзя считать обычной возможностью Java 17.

Text blocks

String json = """
        {
          "status": "ok"
        }
        """;

Text blocks финализированы в Java 15. Отступ определяется общей левой границей, а перевод строки перед закрывающими кавычками влияет на результат.

Изменения платформы

  • усилена инкапсуляция внутренних API JDK: нелегальный reflection может сломаться;
  • восстановлена строгая семантика floating point без необходимости strictfp;
  • добавлены новые интерфейсы генераторов псевдослучайных чисел;
  • RMI Activation удалён;
  • появились контекстные фильтры десериализации;
  • Vector API и Foreign Function & Memory API в 17 ещё были incubator.

Перед миграцией проверяют toolchain, плагины сборки, библиотеки, JVM-флаги, reflection и удалённые модули. Компиляция и тесты важнее простого изменения номера образа.

Связанные темы: Интерфейсы Java, Equals и hashCode, Структура JDK.

Вопросы для собеседования

  1. Главная финальная языковая возможность 17? Sealed classes/interfaces.
  2. Records появились именно в 17? Нет, финализированы в 16, но доступны в 17.
  3. Можно ли record наследовать от своего класса? Нет, он неявно final и наследует Record; интерфейсы реализовывать можно.
  4. Что обязан указать наследник sealed-типа? final, sealed или non-sealed.
  5. Был ли pattern switch стабильным в 17? Нет, только preview.
  6. Почему миграция может сломать reflection? Внутренние JDK packages сильнее инкапсулированы.
  7. Что проверить кроме исходников? Сборку, зависимости, JVM flags, контейнерный образ и интеграционные тесты.