Что будет с 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: примитивные объекты (предварительная версия)
Справочник в пользу выделения кучи примитивного класса