Что будет с Optional после того, как Valhalla появится на Java
«Вальхалла изменит необязательный».
Конечно, но что изменится?
Вы найдете их в сообществе, но никаких конкретных доказательств того, что изменилось.
Нужно ли отказаться от опционального? Как это вообще возможно с текущим кодом, использующим необязательно? Будет ли необязательный параметр по-прежнему обнуляемым?
Давайте углубимся и ответим на них.
Ручной специализированный вариант не будет иметь смысла
Одна из целей Valhalla — улучшить дженерики.
Вы сможете использовать примитивные типы вместо коробочных. Это принесет больше пользы, чем нынешний подход. Использование коробочных типов для дженериков имеет некоторые проблемы с производительностью. Некоторыми из них являются преобразование блоков, выделение кучи и косвенное обращение к памяти.
Даже сегодня можно увидеть потребность в примитивах для дженериков. Коллекции Eclipse используют примитивы в своих картах. И преобразование из их типов в нативную Java не происходит из коробки.
Вы можете проверить это в их реализации для типа карты. Также проблема с конвертацией в родную Map<byte, String>
. Подробнее об этом вопросе следующего вопроса SO.
Как улучшенные универсальные шаблоны влияют на необязательные?
Мы могли бы сделать следующее преобразование без проблем.
OptionalDouble
->Optional<double>
OptionalInt -> Optional<int>
Все опционы ручной работы стали бы бессмысленными. Вместо этого вы можете использовать их специализированный дженерик с примитивом.
Это означало бы, что специализированные классы могут быть полностью удалены. OptionalInt
, OptionalDouble
и им подобные. Тем не менее, чтобы сохранить обратную совместимость, я бы сказал, что они останутся.
Все эти изменения позволили бы сгладить.
Ссылочные типы вместе с Optional
включают выравнивание. Использование примитивных типов также позволит это сделать, а также добавит нулевую безопасность.
Специализированные вручную опции — это все классы, основанные на ценности.
Таким образом, изменение, которое это приносит, заключается в том, что вы избавляетесь от операций с идентификацией. Референтность по-прежнему остается. Таким образом, это делает экземпляры по-прежнему обнуляемыми.
Кроме того, использование примитивов устранило бы необходимость в ящиках. Значение OptionalInt
добавляет бесполезное преобразование из int -> Integer
. С Valhalla это будет удалено.
Почему необязательные экземпляры по-прежнему допускают значение NULL?
В основном, чтобы не сломать существующий код. Несмотря на это, по-прежнему будет возможность объявить необязательный параметр необнуляемым для будущего кода.
Старый необязательный параметр остается обнуляемым, Valhalla необязательный может быть не обнуляемым
Давайте сначала рассмотрим классы значений и примитивные классы.
Некоторые классы значений могут быть примитивными. Экземпляры-примитивы должны иметь значение по умолчанию и не могут содержать значение NULL.
Таким образом, хотя LocalDate
может быть примитивным, хорошего кандидата на значение по умолчанию не существует. Вы бы установили какое-то значение, но это все равно добавило бы двусмысленности.
Это напоминает мне значения по умолчанию для прото-сообщений. Например, поля int в прото-сообщениях заполняются значением по умолчанию 0. То же, что и в Java сегодня. Но для других составных значений значение по умолчанию равно null.
Мы знаем, что Optional
— это класс, основанный на значениях. Тем не менее, будет возможность и для примитивного типа Optional
.
Что изменится, если Optional
станет классом значений?
Одно можно сказать наверняка Optional
не может быть примитивным классом. В качестве ссылочного типа широко используется, и клиенты ожидают, что это останется навсегда.
Итак, нам нужна эталонная проекция. Что это означает? Экземпляр Optional
будет примитивным, но будет передаваться как ссылка.
Эта реализация может сделать это возможным.
sealed interface Optional permits Optional.val {}
primitive class Optional.val implements Optional {...}
Это означает, что мы не сможем иметь обнуляемые экземпляры Optional.val
. Но в результате выполнения может появиться нуль, так как это приведет к возврату к Optional
.
Optional v = findCustomer(); // could be nullable, in existing API even after Valhalla
Optional.val v1 = Optional.of(customer); // not-nullable
После приземления Валгаллы будущие экземпляры Optional
могут быть Optional.val
. И это хорошо сочетается со слоганом Valhalla: 'Коды, как класс, работают как int'.
Optional
станет ссылочным типом. А для примитивного типа Optional
вы должны использовать Optional.val
.
Кто-то может утвердить, что Optional.val
— странное обозначение. В конце концов, мы могли бы использовать Optional
для классов ссылочного типа и optional
для классов примитивного типа. Тем не менее, это вызовет волновой эффект и не даст никаких дополнительных преимуществ.
Что хорошего в этом дизайне?
- Не нарушает существующий код
- Все необязательные экземпляры становятся ref-default, но также могут принимать val-default
- Это изменение не нарушит существующий код, так как все поля ref-default
- Сглаживание в куче, поскольку класс значений лишен идентичности
- Новые необязательные экземпляры будут
Optional.val
по умолчанию
Что происходит с ofNullable
?
Если передать null
Optional#of
, получится NullPointerException
. Вот почему у нас есть Optional#ofNullable
.
Когда появится Valhalla, большинство прибегнет к использованию Optional
для переноса примитивов. По крайней мере, это принесло бы больше пользы, чем упаковка коробочных экземпляров.
Лучше использовать Optional<int>
, чем OptionalInt
или Optional<Integer>
.
Таким образом, при наличии примитивов ofNullable
было бы бессмысленно. По сути, и Optional#of
, и Optional#ofNullable
вызовут NullPointerException
.
Должны быть некоторые различия в использовании ofNullable
для опционов примитивного типа.
Даже если это приведет к проблемам со временем компиляции, это может сбить с толку. Optional#ofNullable
не принимает значения null
.
Когда мы получим новые дженерики, может появиться способ сделать вывод, что примитив Optional
не допускает значение null.
Все эти улучшения должны сделать Optional
быстрее и с ним будет проще работать. Если мы удалим операции тождества, мы получим плоскостность. Если мы удалим ссылочную принадлежность, мы удалим выделение кучи и удалим обнуляемость.
Рекомендации
Обновленные документы State of Valhalla
Новый кандидат JEP: 401: примитивные объекты (предварительная версия)
Справочник в пользу выделения кучи примитивного класса