Должен ли метод поиска возвращать значение null или выдавать исключение, если он не может произвести возвращаемое значение?

Я использую язык Java, у меня есть метод, который должен возвращать объект, если он найден.

Если он не найден, я должен:

  1. вернуть ноль
  2. выбросить исключение
  3. Другие

Какая лучшая практика или идиома?

Что бы вы ни делали, обязательно задокументируйте это. Я думаю, что этот момент более важен, чем какой именно подход является «лучшим».

Rik 07.10.2008 03:04

Это зависит от преобладающих идиом языка программирования. Пометьте этот вопрос тегом языка программирования.

Teddy 02.10.2009 02:41

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

3k- 20.08.2013 15:33

Мне кажется, что на самом деле задается вопрос, следует ли считать исключительным, если сущность не обнаружена, и если да, то почему? Никто не ответил достаточно, как прийти к такому выводу, и теперь вопросы и ответы закрыты. Очень жаль, что индустрия не пришла к консенсусу по этой важной теме. Да, я знаю это зависит. Итак, объясните, почему это зависит от большего, чем «если исключение, бросьте».

crush 09.08.2018 19:19
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
509
4
158 056
36
Перейти к ответу Данный вопрос помечен как решенный

Ответы 36

Я предпочитаю просто возвращать значение NULL и полагаюсь на то, что вызывающий объект обработает его должным образом. Исключением (из-за отсутствия лучшего слова) является то, что я абсолютно «уверен», что этот метод вернет объект. В этом случае отказ является исключительным случаем, который должен и должен бросить.

Будьте совместимы с API, которые вы используете.

Используйте шаблон нулевого объекта или создайте исключение.

Это настоящий ответ. Возвращать null - ужасная привычка ленивых программистов.

jeremyjjbrown 23.05.2013 23:01

Я не могу поверить, что этот ответ еще не был признан лучшим. Это настоящий ответ, и любой из этих подходов чрезвычайно прост и избавляет от лишнего кода или NPE.

Bane 06.09.2013 17:16

Если использовать шаблон нулевого объекта, как отличить случай, когда ключ отображается на нулевой объект, от случая, когда ключ не имеет отображения? Я бы подумал, что возврат бессмысленного объекта будет намного хуже, чем возврат null. Возврат null коду, который не подготовлен к его обработке, обычно приводит к возникновению исключения. Не лучший выбор исключения, но тем не менее исключение. Возврат бессмысленного объекта с большей вероятностью приведет к тому, что код будет неправильно считать бессмысленные данные правильными.

supercat 05.10.2014 02:25

Как будет вести себя нулевой объект при поиске сущности? Например, Person somePerson = personRepository.find("does-not-exist");. Предположим, этот метод возвращает нулевой объект для ID does-not-exist. Каким тогда будет правильное поведение somePerson.getAge()? Прямо сейчас я еще не уверен, что шаблон нулевого объекта - правильное решение для поиска сущностей.

Abdull 15.06.2015 18:23

Вот почему я сказал ИЛИ выбросить исключение, если в вашем случае нет смысла распространять NullPerson. На самом деле, я думаю, что для поиска сущностей лучший подход - это бросить, а затем ваш контроллер / служба / модель / что угодно поймает его и решит, будет ли он повторно генерировать или возвращать нулевой объект. Но да, ваш уровень доступа к данным должен выдавать, исключения легче поймать / отладить, чем задаться вопросом, почему у вас есть нуль где-то в цепочке.

pmlarocque 15.06.2015 21:45

@supercat Нулевой объект должен находиться в другой ветви наследования, например. RealRecord: RecordBase и NullRecord: RecordBase. Тогда все, что принимает RealRecord, не может принимать NullRecord. RecordBase сообщает, что он может быть реальным или нулевым и должен быть абстрактным.

Samuel Danielson 26.04.2020 18:02

@SamuelDanielson: Одна из основных причин, по которой значения NULL полезны, заключается в том, что должен быть способ представления состояния элемента массива, который еще не был написан, и полезно иметь способ копирования состояния элементов массива это могло быть, а могло и не быть написано. Если бы кто-то хотел иметь предварительно заполненный массив, чтобы каждый элемент содержал NullRecord, весь код, который пытается прочитать массив, должен был бы преобразовать ссылку RecordBase в ссылку RealRecord, что не удалось бы, если элемент на самом деле является NullRecord, а я не не вижу, что можно было бы получить.

supercat 26.04.2020 18:14

@supercat Я не нашел языкового тега в вопросе. C++, C# и Rust используют слово «Default» в своих стандартных библиотеках, чтобы отличать от Null в этом случае. Если мы действительно посмотрим на наши варианты на многих языках, мы можем выразить ошибки с помощью исключений, часовых, значений по умолчанию, нулей, типов сумм, объединений, тегированных объединений, свернутых объединений, типов продуктов (атрибут isValid?) И т. Д. насколько вы хотите, чтобы система типов помогла, и сколько ошибок должно быть допущено для расширения непроверенного интерфейса модуля.

Samuel Danielson 26.04.2020 18:42

@SamuelDanielson: Если кто-то хочет иметь возможность иметь T[] с произвольным универсальным типом T, разрешить чтение элементов в тех случаях, когда не может быть записано статически доказано, и определить поведение такого чтения, тогда он должен определить состояние по умолчанию для элементов массива, которые еще не были записаны. C# предоставляет унифицированный синтаксис для ссылки на значение по умолчанию любого произвольного T; для ссылочных типов возвращается значение null; для числовых типов - ноль; для типов структуры он дает структуру со всеми полями, содержащими значения по умолчанию.

supercat 26.04.2020 20:36

Если клиентскому коду важно знать разницу между найденным и не найденным, и это должно быть обычным поведением, тогда лучше вернуть null. Затем клиентский код может решить, что делать.

Обычно он должен возвращать значение null. Код, вызывающий метод, должен решить, выбросить ли исключение или попытаться сделать что-то еще.

Это действительно зависит от того, ожидаете ли вы найти объект или нет. Если вы следите за школой мысли, что исключения следует использовать для обозначения чего-либо, ну, эээ, тогда произошло исключение:

  • Найден объект; вернуть объект
  • Объект не найден; выбросить исключение

В противном случае верните null.

Выбрасывайте исключение только в том случае, если это действительно ошибка. Если ожидается, что объект не существует, верните значение null.

В противном случае это вопрос предпочтений.

Я не согласен. Вы можете создавать исключения как коды состояния: «NotFoundException»

ACV 16.10.2017 16:37

Конечно, это не должно быть вопросом предпочтений. Вот как мы получаем несогласованный код - если не в коде вашей команды, то почти наверняка при переплетении кода других разработчиков с вашим собственным (внешними библиотеками).

crush 09.08.2018 19:21

Я думаю, что обработка нулевого случая намного проще, чем "NotFoundException". Подумайте, сколько строк try-catch вам нужно написать вокруг каждого отдельного запроса на повторное получение, которое вызывает «NotFoundException» ... Мне больно готовить весь этот код на моих глазах.

visc 09.08.2018 23:05

Я хотел бы процитировать Тони Хора: «Я называю это своей ошибкой на миллиард долларов». Я бы не возвращал null, я либо генерирую исключение и обрабатываю его правильно, либо возвращаю пустой объект.

seven 09.09.2019 16:12
Ответ принят как подходящий

Если вы всегда ожидаете найти значение, бросьте исключение, если оно отсутствует. Исключение будет означать, что возникла проблема.

Если значение может отсутствовать или присутствовать и оба значения допустимы для логики приложения, верните значение NULL.

Более важно: что вы делаете в других местах кода? Последовательность важна.

@Ken: +1, было бы неплохо упомянуть, что если вы генерируете исключение, но можете обнаружить его априори (например, HasItem (...)), тогда пользователь должен предоставить указанный метод Has * или Contains.

user7116 07.10.2008 02:29

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

axiom82 30.05.2014 22:50

Вместо того, чтобы возвращать значение или ноль, когда значение отсутствует, рассмотрите возможность возврата Maybe <T>. См. mikehadlow.blogspot.nl/2011/01/monads-in-c-5-maybe.html.

Erwin Rooijakkers 29.09.2015 13:07

В @ErwinRooijakkers способ выбора дизайна, начиная с Java 8, вы также можете вернуть Необязательно <T>

José Andias 27.01.2016 18:27

Перед лицом двусмысленности возникает соблазн выбрать один подход и последовательно придерживаться его. Я считаю, что мы должны хорошенько подумать, какой из них более уместен, и судить об этом в индивидуальном порядке. Контекстуально похожие случаи затем могут обрабатываться согласованным образом, и определение контекста выходит за рамки рассмотрения типов возвращаемых значений.

Kevin Lee 08.09.2016 08:25

Меня это немного беспокоит, каждый ответ перекликается с одной и той же пословицей: «Если что-то особенное, брось». Большинство инженеров знакомы с этим принципом. На мой взгляд, реальный вопрос здесь в том, как определить, считается ли должно быть исключительным. OP ищет лучшая практика, например, в отношении чего-то вроде шаблона репозитория. Считается ли обычно исключительным, что объект не существует с данным первичным ключом? Да, это то, что будет определять его сфера деятельности, но что предлагают большинство экспертов с многолетним опытом? Вот какой ответ мы должны увидеть.

crush 09.08.2018 19:05

Кажется, это действительно вопрос личного мнения. Люди говорят о том, чтобы оставаться последовательными, но ответы здесь даже непоследовательны. Некоторые, кажется, думают, что это правильно, а другие думают, что вы должны вернуть null. И хотя проект вашей команды может оставаться последовательным, в тот момент, когда вы начнете использовать чужую библиотеку, вы можете столкнуться с несогласованностью, потому что не были определены четкие отраслевые требования для этого распространенного сценария. «Если значение может отсутствовать или присутствовать, и оба действительны ... вернуть ноль» Я бы добавил это с помощью Q, как следует определить, действительны ли оба?

crush 09.08.2018 19:14

@crush Я думаю, что руководящим принципом является какие параметры передаются функции. Если вы передаете личность, как вы упоминаете первичный ключ, то это следует считать исключительным, если этот элемент не найден, потому что указывает на несогласованное состояние в системе. Пример: GetPersonById(25) сгенерирует, если этот человек был удален, но GetPeopleByHairColor("red") вернет пустой результат. Итак, я думаю, что параметры что-то говорят об ожиданиях.

John Knoop 01.11.2018 17:40

Последовательность важна!

Yan Khonski 01.02.2019 18:25

Как правило, если метод всегда должен возвращать объект, используйте исключение. Если вы ожидаете случайного появления null и хотите обработать его определенным образом, используйте null.

Что бы вы ни делали, я настоятельно не рекомендую третий вариант: возвращать строку с надписью «WTF».

Плюс один, потому что в старые добрые времена я делал это более пары раз в качестве быстрого грязного «временного» исправления ... плохая идея. Особенно, если его собираются пересмотреть, если вы студент.

rciafardone 13.03.2014 19:48

Я собирался проголосовать против, так как варианты WTF показались мне потрясающими ... но, видимо, у меня есть сердце

swestner 23.09.2015 23:45

бросить новый WtfExcepti?n

Kamafeather 16.01.2018 03:41

Я думаю, было бы полезно, если бы в этом ответе говорилось о причинах, по которым метод всегда будет возвращать объект, а не «случайный нуль». Что оправдывает такую ​​ситуацию? Приведите пример, когда может существовать такое обстоятельство.

crush 09.08.2018 19:23

Зависит от того, что означает, что объект не найден.

Если это нормальное состояние, верните null. Это просто то, что может происходить время от времени, и вызывающие абоненты должны это проверить.

Если это ошибка, то вызовите исключение, вызывающие должны решить, что делать с ошибочным состоянием отсутствия объекта.

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

Как бы вы описали оператор «нормальное состояние дел» и какие критерии вы будете использовать, чтобы отличить его от ошибки.

user1451111 14.06.2018 16:46

Это зависит от характера метода и того, как он будет использоваться. Если это нормальное поведение, когда объект не может быть найден, верните null. Если это нормальное поведение, когда объект всегда найден, вызовите исключение.

Как правило, используйте исключения только тогда, когда возникает что-то исключительное. Не пишите код таким образом, чтобы генерация и перехват исключений была частью его нормальной работы.

Поскольку предполагается, что объекту возвращается Справка, возвращение NULL должно быть нормальным.

Однако, если он возвращает всю чертову штуку (как в C++, если вы это делаете: 'return blah;' вместо 'return & blah;' (или 'blah' - указатель), то вы не можете вернуть NULL, потому что это не типа «объект». В этом случае я бы подошел к проблеме, выбрасывая исключение или возвращая пустой объект, для которого не установлен флаг успеха.

Если не обнаружение, это исключительное событие (т.е. оно должно быть там при нормальных обстоятельствах), бросьте. В противном случае верните значение «не найдено» (может быть нулевым, но не обязательно) или даже пусть метод возвращает логическое значение для найденного / не найденного и параметр out для фактического объекта.

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

Вы также можете открыть метод, возвращающий логическое значение true / false, если этот метод действительно вернет объект, поэтому вам не нужно: а) проверять значение null или б) перехватывать исключение.

«Другой» вариант может заключаться в том, чтобы позволить методу поиска принимать дополнительный параметр с объектом по умолчанию, который будет возвращен, если искомый объект не может быть найден.

В противном случае я бы просто вернул null, если это действительно не исключительный случай, когда объект не найден.

Возвратите значение NULL вместо создания исключения и четко задокументируйте возможность возврата значения NULL в документации по API. Если вызывающий код не соблюдает API и не проверяет регистр NULL, это, скорее всего, все равно приведет к некоему «исключению с нулевым указателем» :)

В C++ я могу придумать 3 различных варианта настройки метода, который находит объект.

Вариант А

Object *findObject(Key &key);

Возвращает null, если объект не может быть найден. Красиво и просто. Я бы пошел с этим. Приведенные ниже альтернативные подходы предназначены для людей, которые не ненавидят out-params.

Вариант Б

void findObject(Key &key, Object &found);

Передайте ссылку на переменную, которая будет получать объект. Метод вызвал исключение, когда объект не может быть найден. Это соглашение, вероятно, более подходит, если на самом деле не ожидается, что объект не будет найден - следовательно, вы генерируете исключение, чтобы указать, что это неожиданный случай.

Вариант C

bool findObject(Key &key, Object &found);

Метод возвращает false, если объект не может быть найден. Преимущество этого варианта перед вариантом A заключается в том, что вы можете проверить случай ошибки за один четкий шаг:

if (!findObject(myKey, myObj)) { ...

Не думайте, что кто-то упоминал накладные расходы при обработке исключений - требуются дополнительные ресурсы для загрузки и обработки исключения, поэтому, если это не настоящее событие, связанное с убийством приложения или остановкой процесса (дальнейшее продвижение принесет больше вреда, чем пользы), я бы предпочел передать обратно Ценность вызывающей среды может интерпретировать так, как считает нужным.

Я согласен с тем, что кажется здесь консенсусом (возврат null, если «не найден» является нормальным возможным результатом, или выбросить исключение, если семантика ситуации требует, чтобы объект всегда был найден).

Однако существует третья возможность, которая может иметь смысл в зависимости от вашей конкретной ситуации. Ваш метод может вернуть какой-либо объект по умолчанию в состоянии «не найден», что позволяет вызывающему коду быть уверенным в том, что он всегда получит действительный объект без необходимости проверки на null или перехвата исключений.

В коде уровня данных я иногда использую следующий код, позволяющий вызывающей стороне решить, означает ли «объект не найден» возникла ошибка.


DataType GetObject(DBConnection conn, string id, bool throwOnNotFound) {
    DataType retval = ... // find object in database
    if (retval != null || ! throwOnNotFound) {
        return retval;
    } else {
        throw new NoRowsFoundException("DataType object with id {id} not found in database");
    }
}

DataType GetObject(DBConnection conn, string id) {
    return GetObject(conn, id, true);
} 

Если null никогда не указывает на ошибку, просто верните null.

Если значение null всегда является ошибкой, вызовите исключение.

Если null иногда является исключением, запрограммируйте две процедуры. Одна процедура выдает исключение, а другая - это логическая тестовая процедура, которая возвращает объект в выходном параметре, а процедура возвращает ложь, если объект не был найден.

Трудно злоупотребить рутиной Try. Очень легко забыть проверить значение null.

Итак, когда null является ошибкой, вы просто пишете

object o = FindObject();

Если нуль не является ошибкой, вы можете написать что-то вроде

if (TryFindObject(out object o)
  // Do something with o
else
  // o was not found

Это было бы более полезным предложением, если бы C# предоставлял реальные кортежи, поэтому мы могли бы избежать использования параметра [out]. Тем не менее, это предпочтительный шаблон, поэтому +1.

Erik Forbes 06.10.2008 23:07

На мой взгляд, лучший подход - попытка. Тогда вам не нужно искать, что произойдет, если объект не может быть возвращен. Используя метод Try, вы сразу знаете, что делать.

OregonGhost 07.10.2008 00:52

напоминает мне find и findOrFail из Laravel Eloquent

javier_domenech 31.05.2018 15:00

@ErikForbes Я знаю, что ваш комментарий старый, но разве не нужно было определить объект с несколькими свойствами, который будет возвращен методом TryFindObject? Кортежи кажутся более ленивой парадигмой для программистов, которые не хотят тратить время на определение объекта, который инкапсулирует несколько значений. По сути, все кортежи в любом случае лежат в основе.

crush 09.08.2018 19:26

@crush - Именованные литералы кортежей - это вариант, ИМО. Это ссылка на асинхронный шаблон Try Get с кортежами. stackoverflow.com/questions/1626597/…

ttugates 09.04.2019 03:10

Или верните вариант

Вариант - это, по сути, контейнерный класс, который заставляет клиента обрабатывать будки. У Scala есть такая концепция, посмотрите ее API.

Затем у вас есть такие методы, как T getOrElse (T valueIfNull) для этого объекта, которые либо возвращают найденный объект, либо все альтернативы, указанные клиентом.

Верните нулевое значение, исключения - это именно то, что: ваш код делает то, чего не ожидают.

это зависит от того, поддерживает ли ваш язык и код: ЛБЫЛ (посмотри, прежде чем прыгнуть) или же EAFP (проще просить прощения, чем разрешения)

LBYL говорит, что вы должны проверить значения (поэтому верните ноль)
EAFP предлагает просто попробовать операцию и посмотреть, не удастся ли она (выбросить исключение)

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


EAFP против LBYL в Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html (Веб-архив)

В некоторых случаях EAFP - единственный значимый подход. Например, в параллельной карте / словаре нет способа спросить, будет ли отображение существовать, когда оно будет запрошено.

supercat 05.10.2014 02:26

В некоторых функциях я добавляю параметр:

..., bool verify = true)

Истина означает выброс, ложь означает возврат некоторого возвращаемого значения ошибки. Таким образом, у того, кто использует эту функцию, есть оба варианта. Значение по умолчанию должно быть истинным для тех, кто забывает об обработке ошибок.

Отсутствие объекта может произойти во время обычных операций и должно быть обработано вызывающей стороной, возвращающей NULL.

Если объект не содержит, это указывает на ошибку вызывающим кодом или внутренним состоянием, тогда выполните assert.

Если объект не содержит, указывает на нечастое событие. (Подобно тому, как кто-то удалил элемент из магазина, в то время как вы одновременно извлекали этот элемент.) Затем создайте исключение.

Просто спросите себя: «Это исключительный случай, когда объект не найден»? Если ожидается, что это произойдет в ходе обычной работы вашей программы, вам, вероятно, не следует создавать исключение (поскольку это не исключительное поведение).

Краткая версия: используйте исключения для обработки исключительного поведения, а не для обработки обычного потока управления в вашей программе.

-Алан.

Исключения должны быть исключительный. Вернуть null если допустимо вернуть нуль.

Более-менее верно. См. boost.org/community/error_handling.html

Martin Cote 07.10.2008 04:20

Исключения связаны с проектированием по контракту.

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

1) все входные данные метода действительны, и в этом случае вы должны вернуть null, если объект не найден.

2) действителен только некоторый ввод, то есть тот, который приводит к найденному объекту. В этом случае вы ДОЛЖНЫ предложить второй метод, который позволяет вызывающему абоненту определить, будет ли его ввод правильным. Например

is_present(key)
find(key) throws Exception

ЕСЛИ и ТОЛЬКО ЕСЛИ вы предоставляете оба метода 2-го контракта, вам разрешено генерировать исключение, ничего не найдено!

Вот еще пара предложений.

При возврате коллекции избегайте возврата null, возвращайте пустую коллекцию, которая упрощает работу с перечислением без предварительной проверки на null.

Некоторые API .NET используют шаблон параметра thrownOnError, который дает вызывающей стороне выбор, действительно ли это исключительная ситуация или нет, если объект не найден. Type.GetType является примером этого. Другой распространенный шаблон с BCL - это шаблон TryGet, в котором возвращается логическое значение, а значение передается через выходной параметр.

В некоторых случаях вы также можете рассмотреть шаблон «Нулевой объект», который может быть либо значением по умолчанию, либо версией без поведения. Ключ в том, чтобы избегать нулевых проверок по всей базе кода. См. Здесь для получения дополнительной информации http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx

Я просто хотел резюмировать варианты, упомянутые ранее, добавив несколько новых:

  1. вернуть ноль
  2. выбросить исключение
  3. использовать шаблон нулевого объекта
  4. предоставить логический параметр вашему методу, чтобы вызывающий мог выбрать, хочет ли он, чтобы вы сгенерировали исключение
  5. предоставить дополнительный параметр, поэтому вызывающий может установить значение, которое он получит обратно, если значение не найдено

Или вы можете комбинировать эти варианты:

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

Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);

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

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

Мне нравятся четкие имена функций, особенно orCreate и orDefault.

marcovtwout 14.07.2015 12:10

Большая часть этого может быть более четко написана с помощью Expected<T> findObject(String), где Expected<T> имеет функции orNull(), orThrow(), orSupplied(Supplier<T> supplier), orDefault(T default). Это абстрагирует получение данных от обработки ошибок.

WorldSEnder 06.10.2015 05:39

До сих пор я не знал об Expected <T>. Кажется, я новичок и, возможно, не существовал, когда писал исходный ответ. Может быть, тебе стоит сделать свой комментарий правильным ответом.

Lena Schimmel 06.10.2015 14:57

Кроме того, Expected <T> - это шаблон C++. Есть ли его реализации на других объектно-ориентированных языках?

Lena Schimmel 06.10.2015 14:58

В Java 8 также возможен возврат Optional <T> (на других языках он называется Maybe <T> и т. д.). Это ясно указывает вызывающему, что возврат ничего не возможен и не будет компилироваться, если вызывающий не обработал эту возможность, в отличие от null, который (в любом случае в Java) будет компилироваться, даже если вызывающий его не проверит. .

Some Guy 22.01.2019 15:54

имея в виду только случай, когда null не считается исключительным поведением, я определенно поддерживаю метод try, это ясно, нет необходимости «читать книгу» или «смотреть перед прыжком», как было сказано здесь

так в основном:

bool TryFindObject(RequestParam request, out ResponseParam response)

а это значит, что код пользователя тоже будет понятен

...
if (TryFindObject(request, out response)
{
  handleSuccess(response)
}
else
{
  handleFailure()
}
...

Предпочитать возвращать null -

Если вызывающий использует его без проверки, исключение все равно произойдет прямо здесь.

Если вызывающий на самом деле не использует его, не облагайте его налогом блок try / catch.

К сожалению, JDK несовместим, если вы пытаетесь получить доступ к несуществующему ключу в пакете ресурсов, вы получаете исключение не найдено, и когда вы запрашиваете значение из карты, вы получаете null, если он не существует. Поэтому я бы изменил ответ победителя на следующий: если найденное значение может быть нулевым, затем вызвать исключение, если оно не найдено, в противном случае вернуть null. Поэтому следуйте правилу с одним исключением: если вам нужно знать, почему значение не найдено, всегда вызывайте исключение или ..

Преимущества выброса исключения:

  1. Более чистый поток управления в вашем вызывающем коде. Проверка на null вводит условную ветвь, которая изначально обрабатывается try / catch. Проверка на null не указывает на то, что вы проверяете - проверяете ли вы на null, потому что ищете ожидаемую ошибку, или вы проверяете на null, чтобы не передавать его дальше в нисходящей цепочке ?
  2. Устраняет двусмысленность того, что означает «ноль». Является ли NULL представлением ошибки или является NULL, что фактически хранится в значении? Трудно сказать, когда у вас есть только одна вещь, на которой основывается это определение.
  3. Повышена согласованность поведения методов в приложении. Исключения обычно раскрываются в сигнатурах методов, поэтому вы лучше понимаете, для каких крайних случаев используются методы в учетной записи приложения и на какую информацию ваше приложение может реагировать предсказуемым образом.

Дополнительные объяснения с примерами см .: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/

+1, потому что пункт 2 отличный - ноль не имеет того же значения, что и не найдено. Это становится более важным при работе с динамическими языками, где Null фактически может быть объектом, который хранится / извлекается функцией - и в этом случае

Adam Terrey 13.10.2015 07:17

+1 за пункт №2. Нулевое значение является ошибкой? Имеет ли значение null то, что хранится для данного ключа? Нулевое значение указывает на то, что ключ не существует? Это настоящая цепочка вопросов, из которых ясно, что возвращение null почти никогда не бывает правильным. Это, вероятно, лучший ответ здесь, поскольку все остальные только что подбрасывали двусмысленное «Если это исключительное, бросайте»

crush 09.08.2018 19:37

Однако исключения могут привести к снижению производительности по сравнению с возвратами (например, в Java). И непроверенные исключения (например, в Java) могут появляться в непредусмотренных местах.

tkruse 19.11.2020 07:54

Если метод возвращает коллекцию, то верните пустую коллекцию (как сказано выше). Но, пожалуйста, не Collections.EMPTY_LIST или тому подобное! (в случае Java)

Если метод извлекает один объект, у вас есть несколько вариантов.

  1. Если метод всегда должен находить результат, и это реальный случай исключения, когда не удается найти объект, тогда вы должны выбросить исключение (в Java: пожалуйста, не отмеченное исключение)
  2. (Только для Java). Если вы можете допустить, что метод выдает проверенное исключение, выбросьте исключение ObjectNotFoundException для конкретного проекта или подобное. В этом случае компилятор сообщает вам, если вы забудете обработать исключение. (Я предпочитаю работать с ненайденными вещами в Java.)
  3. Если вы говорите, что все в порядке, если объект не найден, а имя вашего метода похоже на findBookForAuthorOrReturnNull (..), вы можете вернуть значение null. В этом случае сильно рекомендуется использовать какую-либо статическую проверку или проверку компилятора, которая предотвращает разыменование результата без нулевой проверки. В случае Java это может быть, например. FindBugs (см. DefaultAnnotation в http://findbugs.sourceforge.net/manual/annotations.html) или IntelliJ-Checking.

Будьте осторожны, если решите вернуть null. Если вы не единственный программист в проекте, вы получите NullPointerExceptions (на Java или на других языках) во время выполнения! Поэтому не возвращайте значения NULL, которые не проверяются во время компиляции.

Нет, если код был написан правильно, ожидая null. Подробнее см. В ответе, получившем наибольшее количество голосов.

Andrew Barber 21.08.2012 17:19

Но только если вы убедитесь, что во время компиляции проверяются все значения NULL. Это можно сделать, используя FindBugs @NutNull на уровне пакета и пометив свой метод как «может возвращать null». Или использовать такой язык, как Kotlin или Nice. Но гораздо проще не возвращать null.

iuzuz 21.08.2012 17:44

«Проще», может быть. Но часто совершенно неверно

Andrew Barber 21.08.2012 17:46

Извините, но что не так, если метод, обещающий найти книгу, не может их найти и выдает исключение? Вы знаете "ошибку на миллиард долларов"? infoq.com/presentations/…

iuzuz 21.08.2012 17:56

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

Andrew Barber 21.08.2012 18:01

Ответ, получивший наибольшее количество голосов, не должен быть единственно правильным. Я не согласен с ответом. Также с этим не согласны Роберт С. Мартин (в книге «Чистый код: руководство по Agile Software Craftsmanshi») и Майкл Фезерс. А новые языки программирования, такие как Kotlin и Nice, подписываются на просмотр. И. Возможно, я слишком это принимаю близко к сердцу, но почему вы проголосовали против меня? Я не нарушал правила и мой ответ не так уж плох.

iuzuz 21.08.2012 19:35

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

Andrew Barber 21.08.2012 20:40

Я переписал ответ. Предыдущий ответ был только для Java.

iuzuz 22.08.2012 14:02

Если вы используете библиотеку или другой класс, который генерирует исключение, вы должны перебросить его. Вот пример. Example2.java похожа на библиотеку, а Example.java использует ее объект. Main.java - это пример обработки этого исключения. Вы должны показать значимое сообщение и (при необходимости) трассировку стека пользователю на вызывающей стороне.

Main.java

public class Main {
public static void main(String[] args) {
    Example example = new Example();

    try {
        Example2 obj = example.doExample();

        if (obj == null){
            System.out.println("Hey object is null!");
        }
    } catch (Exception e) {
        System.out.println("Congratulations, you caught the exception!");
        System.out.println("Here is stack trace:");
        e.printStackTrace();
    }
}
}

Example.java

/**
 * Example.java
 * @author Seval
 * @date 10/22/2014
 */
public class Example {
    /**
     * Returns Example2 object
     * If there is no Example2 object, throws exception
     * 
     * @return obj Example2
     * @throws Exception
     */
    public Example2 doExample() throws Exception {
        try {
            // Get the object
            Example2 obj = new Example2();

            return obj;

        } catch (Exception e) {
            // Log the exception and rethrow
            // Log.logException(e);
            throw e;
        }

    }
}

Example2.java

 /**
 * Example2.java
 * @author Seval
 *
 */
public class Example2 {
    /**
     * Constructor of Example2
     * @throws Exception
     */
    public Example2() throws Exception{
        throw new Exception("Please set the \"obj\"");
    }

}

Если исключение, которое должно быть выброшено из функции, не является исключением во время выполнения, и ожидается, что вызывающий объект обработает его (вместо того, чтобы просто завершить программу), то вместо того, чтобы генерировать исключение из внутренней подсистемы, которого вызывающий не может ожидать, было бы лучше заключить внутреннее исключение во внешнее проверенное исключение, при этом «связав» внутреннее исключение, чтобы кто-нибудь, занимающийся отладкой, мог выяснить, почему было сгенерировано внешнее исключение. Например, example1 может использовать 'throw new MyCheckedException ("Пожалуйста, установите \" obj \ "", e)', чтобы включить 'e' в выброшенное исключение.

Some Guy 22.01.2019 15:49

Другие вопросы по теме