В Java появятся записи и запечатанные типы

В багтрекере OpenJDK появился новый черновик JEP, в котором специфицируются новые языковые конструкции Java: записи и запечатанные типы. Идея их введения была предложена полтора года назад и была описана в исследовательском документе. Наконец, после долгих дискуссий и экспериментов она достигла достаточного уровня зрелости для того, чтобы с большой уверенностью сказать, что она будет реализована в одной из будущих версий Java.

Записи (records) позволят очень компактно объявлять классы, которые являются простыми носителями данных:

record Range(int lo, int hi) {
    public Range {
        if (lo > hi) {
            throw new IllegalArgumentException(
                String.format("(%d,%d)", lo, hi));
        }
    }
}

Сейчас такой класс Range реализуется чрезвычайно многословно, поскольку автору кода необходимо самому написать конструктор, методы доступа к полям, equals(), hashCode() и toString(). Это может раздражать и читателя, ведь эти члены не содержат в себе никакой особо полезной смысловой нагрузки. В записях же все эти члены генерируются компилятором автоматически и поэтому экономят время и строки кода.

Записи имеют следующие особенности:

  • Они иммутабельны (все поля становятся final).
  • От них нельзя отнаследоваться (они являются final).
  • Они сами не могут отнаследоваться от классов.
  • Если записи являются вложенными, то они являются static.
  • Они не могут содержать дополнительных полей.
  • Они могут содержать явный конструктор по умолчанию (в котором можно, например, сделать валидацию полей).

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

Вторая конструкция, тесно связанная с записями – это запечатанные типы (sealed types). Такие типы накладывают ограничение на типы, которые могут от них наследоваться. Делается это одним из двух способов. Первый способ – с помощью ключевого слова permits:

sealed interface Node permits A, B, C { ... }

В этом случае от интерфейса Node не могут быть отнаследованы никакие другие типы кроме A, B и C.

Второй способ – без использования ключевого слова permits. Тогда список наследников будет ограничен только теми типами, которые находятся в той же единице компиляции.

Запечатанные типы имеют следующие особенности:

  • От них не могут быть отнаследованы анонимые классы и лямбды.
  • Их абстрактные подтипы неявно являются запечатанными (но можно переопределить с помощью ключевого слова non-sealed).
  • Их конкретные подтипы неявно являются final.

Записи и запечатанные типы вместе являются реализацией концепции алгебраических типов данных в Java. Поскольку для комфортной работы с алгебраическими типами данных также нужен паттерн-матчинг, то в будущем записи предлагается снабдить деконструирующими паттернами, а для запечатанных типов разработать механизм проверки exhaustiveness в switch-выражениях.

Подписывайтесь на канал в Telegram, чтобы не пропускать новости.

Все материалы на этом сайте выложены под лицензией CC BY-SA 4.0
© Евгений Козлов, 2017-2020