Класс Optional, представленный в Java 8, был одной из самых противоречивых функций, представленных в этой версии языка. Хотя мне нравится больше вещей об этом новом классе Java, чем мне не нравится, есть несколько вещей, которые следует учитывать при использовании его в качестве return
типа в методах Java. Я обсуждаю некоторые из них в этом посте, но не обсуждаю спор о том, следует ли ограничивать использование Optional
в качестве возвращаемого типа. Я также предполагаю, что Optional
используется только в качестве возвращаемого типа, когда ожидается, что в некоторых случаях этот метод не должен иметь значения для возврата. Наконец, эти наблюдения применимы и к другим типам, и к непосредственному использованию null
в Java, но Optional
подчеркивает и конкретно иллюстрирует эти наблюдения.
Одиночные и множественные возвраты
В общем сообществе разработчиков программного обеспечения и сообществе разработчиков Java в течение некоторого времени велась дискуссия (« религиозная война ») о том, следует ли писать методы для return
только один раз (не считая исключения в этом обсуждении). С одной стороны, Егор Бугаенко утверждает, что « многие операторы возврата являются плохой идеей в ООП », Том Даллинг утверждает, что « иметь одну точку выхода (возврата) из функции — это хорошо », и многие утверждают, что несколько операторов return
часто указать необходимость этого метода для рефакторинга . С другой стороны, Брюс Экель утверждает, что множественные операторы return
могут сделать код «более понятным», Тейлор Готье утверждает, что « максима » «Метод должен иметь одну и только одну точку выхода», «не может быть более неправильным», Питер Ричи утверждает, что строгое соблюдение единственного выхода может привести к тому, что сегодня код будет «менее читабелен» на «объектно-ориентированных языках», а Марк Левисон обрисовывает в общих чертах « некоторые причины, по которым мне не нравится аргумент единого выхода ».
В посте « Множественные возвратные операторы » Николай Парлог пишет об истории и соображениях, которые необходимо сделать в связи с идеей метода, возвращаемого только один раз. Он включает в себя раздел «Ситуации для множественных отчетов о возвратах», в котором он описывает «несколько видов ситуаций, в которых метод может извлечь выгоду из множественных отчетов о доходах». Мое лучшее предположение состоит в том, что многие разработчики чувствуют то же, что и я, а именно, что «это зависит» при принятии решения, должен ли конкретный метод иметь только один оператор return
или должен иметь более одного оператора return
.
Поскольку я начал чаще использовать Optional в Java 8 для возвращаемых типов моих методов, я обнаружил, что использование Optional в качестве возвращаемого типа является еще одним соображением, которое необходимо учитывать при принятии решения о возврате из метода один или несколько раз.
Когда объявляется, что метод Java возвращает Optional
, важно полностью понимать, что это не мешает разработчику, пишущему этот метод, возвращать null
. Возвращаемый Optional
является ссылочным типом и, как и любой ссылочный тип, может иметь значение null
. Крайне важно, чтобы разработчик, пишущий метод, который возвращает Optional
НИКОГДА не должен иметь этот метод, возвращающий null
[ Optional.empty () обычно должен возвращаться вместо этого]. Я собираюсь повторить этот пункт с двумя цитатами:
- Выделенное предложение из пункта № 55 в Effective Java , третье издание : « Никогда не возвращайте нулевое значение из метода
Optional
возврата. « - Правило № 1 Стюарта Маркса об использовании
Optional
: «Никогда, никогда не используйте null для необязательной переменной или возвращаемого значения».
Один из аргументов против нескольких операторов return в методе заключается в том, что он усложняет распознавание того, что возвращается в каждом случае (чтобы найти все возможные сценарии возврата). Использование Optional
в качестве типа возврата является конкретным примером, иллюстрирующим это. Хотелось бы убедиться, что в некоторых случаях метод не возвращает null
а в других случаях Optional
экземпляр. Компилятору, конечно, все равно, что возвращается в каждом случае.
Один из подходов к решению этой проблемы состоит в том, чтобы возвращаться из метода только один раз, и тогда разработчик, пишущий код, и разработчик, проверяющий код, могут легко убедиться, что значение null
не возвращено. Этим разработчикам нужно искать только вызов Optional.of (T), вызов Optional.ofNullable (T) или вызов Optional.empty () .
Работа с локальной переменной базового типа данных в методе
Такой подход, позволяющий избежать случайного возврата null
вместо пустого Optional
лучше всего работает, когда создается Optional
экземпляр в точке возврата. Другими словами, я считаю, что лучше работать с типом, обернутым Optional
во всем методе, а затем поместить его в Optional
в последний возможный момент. Следующий листинг кода содержит смехотворно тривиальные примеры этого.
Примеры объявления локальной переменной, которая в конечном итоге возвращается как необязательная
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/** * Provides the middle name if it exists. * * @return Middle name if it exists or empty if it doesn't exist. */ public Optional<String> determineMiddleName1() { String middleName; // Do whatever logic is necessary return Optional.ofNullable(middleName); } /** * Provides the middle name if it exists. * * @return Middle name if it exists or empty if it doesn't exist. */ public Optional<String> determineMiddleName2() { Optional<String> middleName; // Do whatever logic is necessary return middleName; } |
В приведенном выше коде метод determineMiddleName 1 ()
работает с локальной переменной базового типа. Это обычно легче установить / заполнить, чем Optional
и использование Optional.isNullable()
в конце гарантирует, что даже null
middleName будет возвращено как «пустое» Optional
вместо null
.
Метод determineMiddleName 2 ()
в вышеприведенном коде объявляет свою локальную переменную, которая в конечном итоге будет возвращена как Optional<String>
а затем возвращает эту ссылку в конце метода.
Избегайте инициализации локальной переменной по умолчанию
Поскольку метод determineMiddleName 2 ()
написан выше, компилятор поможет убедиться, что локальная переменная «middleName» установлена на что-то (даже если это «что-то» равно null
), но разработчик выбрал инициализацию этой переменной «middleName» для null
, компилятор не будет иметь проблем с этим. Если локальная переменная должна быть инициализирована по какой-либо причине, было бы лучше инициализировать ее в Optional.empty()
вместо null
. Если бы разработчик решил инициализировать эту переменную с помощью Optional.empty()
, для второго примера все еще возможно «сбросить» локальную переменную на null
позже в методе.
Это обсуждение приводит меня к трем несомненным замечаниям относительно использования Optional
в качестве типа возврата метода в Java.
- Влияние одинарного или множественного
return
на возможность случайного возвратаnull
вместо «пустого» или другогоnull
Optional
ссылка должна учитываться при принятии решения о том, имеет ли смысл одиночный или множественный возврат. - Часто будет легче обеспечить возврат ссылки
Optional
, чем возвращениеnull
, работая с базовым типом во всем методе и создавая экземпляр возвращаемогоOptional
в самый последний момент (обычно при егоreturn
). - Локальная переменная типа
Optional
которая в конечном итоге должна быть возвращена из метода, НИКОГДА не должна изначально присваиватьсяnull
даже если «известно», что она будет переустановлена соответствующим образом. Может быть, лучше вообще не определять его, чтобы компилятор обеспечивал его установку в каждой «ветви» потока кода. По крайней мере, если она должна быть инициализирована, локальная переменная типаOptional
должна быть инициализирована какOptional.empty()
а не какnull
.
Эти наблюдения могут быть объединены. Например, когда определено, что метод должен иметь несколько возвратов (например, для реализации защитных предложений ), можно возвращать соответствующие null
Optional
ссылки в точке каждого возврата и не инициализировать локальную переменную до тех пор, пока она не понадобится (после прохождения через охранники). Это иллюстрируется следующим нелепо надуманным примером.
Пример избегания возврата нуля с множественными операторами возврата
01
02
03
04
05
06
07
08
09
10
11
|
public Optional<String> getGuardedData( final String input) { if (input == null ) { return Optional.empty(); } String data; // Do whatever logic is necessary return Optional.ofNullable(data); } |
Я обнаружил, что класс Optional
, при правильном использовании в качестве типа возврата метода, может сделать код клиента более читабельным из-за его большей беглости. Однако для достижения максимального значения Optional
должен применяться с такой дисциплиной, чтобы клиенты кода могли ожидать, что возвращаемый Optional
никогда не будет null
. В этом посте рассмотрены некоторые соображения, которые могут помочь гарантировать, что значение null
никогда не будет возвращено методом, который объявляет себя как возвращающий Optional
. Без уверенности в том, что метод никогда не вернет null
, использование Optional
в качестве возвращаемого типа только ухудшает ситуацию, поскольку вынуждает клиента сначала проверять null
Optional
прежде чем вызывать один из методов этого Optional
. Это делает вызывающий код менее беглым .
Опубликовано на Java Code Geeks с разрешения Дастина Маркса, партнера нашей программы JCG . См. Оригинальную статью здесь: Соображения при возврате Java 8 необязательно из метода
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |