# Optional & null-safety
TL;DR:

Рекомендуется использовать **Optional** только в качестве возвращаемых значений методов, там где удобно явно подчеркнуть, что метод
может не вернуть реального значения. Если метод возвращает контейнерный тип, то следует возвращать пустой контейнер, вместо **Optional**.
Для возвращения опциональных примитивных типов рекомендуется использовать специальные классы ```OptionalInt```, ```OptionalLong``` и т.д.

Не рекомендуется использовать **Optional** в качестве полей классов и аргументов методов.

Рекомендуется использовать аннотации [@NonNullApi](https://a.yandex-team.ru/arc/trunk/arcadia/library/java/annotations/src/main/java/ru/yandex/lang/NonNullApi.java),
[@NonNullFields](https://a.yandex-team.ru/arc/trunk/arcadia/library/java/annotations/src/main/java/ru/yandex/lang/NonNullFields.java),
```@Nullable``` и настроить синтаксические проверки для повышения null-safety в вашем коде. Стоит писать код, считая, что по умолчанию все не null, наиболее лаконично это можно отразить аннотациями ````@NonNullApi````/````@NonNullFields````, которые выставлены на уровне пакетов.
Чтобы указать, что поле или аргумент метода может быть null, рекомендуется использовать аннотацию ```@Nullable```.

## Мотивация
Данные советы дают создатели языка java и их поддерживает мировое сообщество.

**Возвращаемое значение**
- если метод может не вернуть реальное значение, то зачастую удобнее возвращать ```Optional```, а не null (по декларации сразу будет ясно,
  что значение может быть пустым) и именно для этого исходно ```Optional``` добавлялся в язык java                        
- если метод возвращает контейнерный тип, то нужно возвращать пустой контейнер вместо ```Optional``` (легко проверить, что он пустой,
  тут не может быть проблем с NPE)
- возвращаемое значение из метода обычно коротко живущее (в отличие от полей класса), поэтому объект ```Optional``` скоро будет собран gc
- для возвращения примитивных типов следует использовать специальные классы ```OptionalInt```, ```OptionalLong``` и тд
- если вы все-таки используете null в качестве возвращаемых значений, то стоит проставить аннотацию ```@Nullable```

**Поля классов**
- с ```Optional``` могут быть проблемы со сериализацией полей класса и при использовании reflection нужно быть более аккуратным
- если объект долгоживущий, то на Optional будут лишний расход по памяти, особенно это может быть критично, если таких объектов много (например, в кешах)
- рекомендуется использовать аннотацию ```@NonNullFields``` на уровне пакета, чтобы подчеркнуть, что по умолчанию все поля не могут быть null,
  но если поле может быть null, то следует указать аннотацию ```@Nullable``` у него
- опять же, создатели языка говорят о том, что исходно Optional не был предназначен для этой цели, но если вы все же решите
  использовать его для полей класса, то обязательно проверьте, что все используемые библиотеки с ним нормально будут работать

**Аргументы методов**
- нужно делать дополнительный боксинг и код становится менее читабельным
- лучше использовать overload методов, если есть несколько опциональных параметров
- там, где нельзя использовать overload методов, чтобы избежать необходимость передачи null параметров,
  рекомендуется использовать аннотацию ```@Nullable```
- чтобы подчеркнуть, что принимаемые параметры не могут быть null, рекомендуется использовать аннотацию ```@NonNullApi```
  или ```@ParametersAreNonnullByDefault```

**Аннотации**
- [jsr305](https://www.jcp.org/en/jsr/detail%3Fid%3D305) содержит набор аннотаций ```@Nullable```/```@NonNull```/```@ParametersAreNonnullByDefault```
- в spring добавили дополнительные аннотации, чтобы NonNull проверки можно было сделать еще более лаконичными ```@NonNullApi```/```@NonNullFields```
- дизайн языка java говорит, что любой объект может быть null, с этой точки зрения стоит специально отмечать только те поля, которые не могу быть null.
  С другой стороны, в большинстве случаев поля классов и аргументы методов, как раз не могут быть null и добавление везде аннотации ```@NonNull``` добавляет лишнего "шума" в код;
- мы рекомендуем использовать аннотации ```@NonNullApi```/```@NonNullFields``` на уровне пакетов или классов, чтобы
  не добавлять аннотацию ```@NonNull``` всюду, но так как они не входят в jsr305, мы вынесли их [отдельно в аркадии](https://a.yandex-team.ru/arc/trunk/arcadia/library/java/annotations/src/main/java/ru/yandex/lang),
  независимо от spring;
- ```@ParametersAreNonnullByDefault``` входит в jsr305, ее можно использовать, как частичную альтернативу ```@NonNullApi```;
- ```@NonNull``` при использовании вместе с  lombok, кроме синтаксических проверок на уровне IDEA и findbugs, добавляет еще
  и runtime проверки на null, где это необходимо можно их использовать, но сами разработчики lombok
  [не рекомендуют](https://github.com/rzwitserloot/lombok/issues/2310) вставлять их повсеместно, так как это может существенно
  повлиять на performance программы;
- в тех местах, где все-таки может быть null рекомендуется использовать аннотацию ```@Nullable```.


## Option в iceberg
В [bolts](https://bitbucket.org/stepancheg/bolts/wiki/Option) еще до появления java8 был аналогичный ```Optional``` класс ```Option```.
Местами он даже удобнее класса из java, но для общей совместимости лучше стараться использовать ```Optional```.
При написании общих библиотек в их интерфейсах не должно быть ```Option```.

Кроме того, исторически в iceberg сообществе ```Option``` активно использовался в полях классов и аргументах методов.
Была парадигма: все что может быть null, должно быть ```Option```. Тем не менее мировые практики идут в разрез с этим подходом,
поэтому от него рекомендуется уходить.

## Ссылки:
* [Brian Goetz, Java Architect](https://stackoverflow.com/a/26328555)
* [Stephen Coleburne, joda-time](https://blog.joda.org/2015/08/java-se-8-optional-pragmatic-approach.html?showComment=1444902982307#c4835539794059692524)
* [Daniel Olszewski](https://stackoverflow.com/a/39005452)
* [Jetbrains про Optional](https://blog.jetbrains.com/idea/2016/07/java-8-top-tips/)
* [И еще про инспекции в jetbrains](https://www.wangler.io/blog/2017/java8-optionals.html)
* [Sonar инспекции](https://rules.sonarsource.com/java/RSPEC-3553)
* [jsr305](https://www.jcp.org/en/jsr/detail%3Fid%3D305)
* [@NonNull в lombok](https://github.com/rzwitserloot/lombok/issues/2310)
* [Spring Null-Safety](https://www.baeldung.com/spring-null-safety-annotations)
