Я использую язык Java, у меня есть метод, который должен возвращать объект, если он найден.
Если он не найден, я должен:
Какая лучшая практика или идиома?
Это зависит от преобладающих идиом языка программирования. Пометьте этот вопрос тегом языка программирования.
Возврат null может означать только успех или неудачу, которые очень часто не содержат много информации (некоторые методы могут давать сбой по-разному). Библиотеки должны лучше генерировать исключения, чтобы сделать ошибки явными, и таким образом основная программа может решить, как обрабатывать ошибку на более высоком уровне (в отличие от встроенной логики обработки ошибок).
Мне кажется, что на самом деле задается вопрос, следует ли считать исключительным, если сущность не обнаружена, и если да, то почему? Никто не ответил достаточно, как прийти к такому выводу, и теперь вопросы и ответы закрыты. Очень жаль, что индустрия не пришла к консенсусу по этой важной теме. Да, я знаю это зависит. Итак, объясните, почему это зависит от большего, чем «если исключение, бросьте».




Я предпочитаю просто возвращать значение NULL и полагаюсь на то, что вызывающий объект обработает его должным образом. Исключением (из-за отсутствия лучшего слова) является то, что я абсолютно «уверен», что этот метод вернет объект. В этом случае отказ является исключительным случаем, который должен и должен бросить.
Будьте совместимы с API, которые вы используете.
Используйте шаблон нулевого объекта или создайте исключение.
Это настоящий ответ. Возвращать null - ужасная привычка ленивых программистов.
Я не могу поверить, что этот ответ еще не был признан лучшим. Это настоящий ответ, и любой из этих подходов чрезвычайно прост и избавляет от лишнего кода или NPE.
Если использовать шаблон нулевого объекта, как отличить случай, когда ключ отображается на нулевой объект, от случая, когда ключ не имеет отображения? Я бы подумал, что возврат бессмысленного объекта будет намного хуже, чем возврат null. Возврат null коду, который не подготовлен к его обработке, обычно приводит к возникновению исключения. Не лучший выбор исключения, но тем не менее исключение. Возврат бессмысленного объекта с большей вероятностью приведет к тому, что код будет неправильно считать бессмысленные данные правильными.
Как будет вести себя нулевой объект при поиске сущности? Например, Person somePerson = personRepository.find("does-not-exist");. Предположим, этот метод возвращает нулевой объект для ID does-not-exist. Каким тогда будет правильное поведение somePerson.getAge()? Прямо сейчас я еще не уверен, что шаблон нулевого объекта - правильное решение для поиска сущностей.
Вот почему я сказал ИЛИ выбросить исключение, если в вашем случае нет смысла распространять NullPerson. На самом деле, я думаю, что для поиска сущностей лучший подход - это бросить, а затем ваш контроллер / служба / модель / что угодно поймает его и решит, будет ли он повторно генерировать или возвращать нулевой объект. Но да, ваш уровень доступа к данным должен выдавать, исключения легче поймать / отладить, чем задаться вопросом, почему у вас есть нуль где-то в цепочке.
@supercat Нулевой объект должен находиться в другой ветви наследования, например. RealRecord: RecordBase и NullRecord: RecordBase. Тогда все, что принимает RealRecord, не может принимать NullRecord. RecordBase сообщает, что он может быть реальным или нулевым и должен быть абстрактным.
@SamuelDanielson: Одна из основных причин, по которой значения NULL полезны, заключается в том, что должен быть способ представления состояния элемента массива, который еще не был написан, и полезно иметь способ копирования состояния элементов массива это могло быть, а могло и не быть написано. Если бы кто-то хотел иметь предварительно заполненный массив, чтобы каждый элемент содержал NullRecord, весь код, который пытается прочитать массив, должен был бы преобразовать ссылку RecordBase в ссылку RealRecord, что не удалось бы, если элемент на самом деле является NullRecord, а я не не вижу, что можно было бы получить.
@supercat Я не нашел языкового тега в вопросе. C++, C# и Rust используют слово «Default» в своих стандартных библиотеках, чтобы отличать от Null в этом случае. Если мы действительно посмотрим на наши варианты на многих языках, мы можем выразить ошибки с помощью исключений, часовых, значений по умолчанию, нулей, типов сумм, объединений, тегированных объединений, свернутых объединений, типов продуктов (атрибут isValid?) И т. Д. насколько вы хотите, чтобы система типов помогла, и сколько ошибок должно быть допущено для расширения непроверенного интерфейса модуля.
@SamuelDanielson: Если кто-то хочет иметь возможность иметь T[] с произвольным универсальным типом T, разрешить чтение элементов в тех случаях, когда не может быть записано статически доказано, и определить поведение такого чтения, тогда он должен определить состояние по умолчанию для элементов массива, которые еще не были записаны. C# предоставляет унифицированный синтаксис для ссылки на значение по умолчанию любого произвольного T; для ссылочных типов возвращается значение null; для числовых типов - ноль; для типов структуры он дает структуру со всеми полями, содержащими значения по умолчанию.
Если клиентскому коду важно знать разницу между найденным и не найденным, и это должно быть обычным поведением, тогда лучше вернуть null. Затем клиентский код может решить, что делать.
Обычно он должен возвращать значение null. Код, вызывающий метод, должен решить, выбросить ли исключение или попытаться сделать что-то еще.
Это действительно зависит от того, ожидаете ли вы найти объект или нет. Если вы следите за школой мысли, что исключения следует использовать для обозначения чего-либо, ну, эээ, тогда произошло исключение:
В противном случае верните null.
Выбрасывайте исключение только в том случае, если это действительно ошибка. Если ожидается, что объект не существует, верните значение null.
В противном случае это вопрос предпочтений.
Я не согласен. Вы можете создавать исключения как коды состояния: «NotFoundException»
Конечно, это не должно быть вопросом предпочтений. Вот как мы получаем несогласованный код - если не в коде вашей команды, то почти наверняка при переплетении кода других разработчиков с вашим собственным (внешними библиотеками).
Я думаю, что обработка нулевого случая намного проще, чем "NotFoundException". Подумайте, сколько строк try-catch вам нужно написать вокруг каждого отдельного запроса на повторное получение, которое вызывает «NotFoundException» ... Мне больно готовить весь этот код на моих глазах.
Я хотел бы процитировать Тони Хора: «Я называю это своей ошибкой на миллиард долларов». Я бы не возвращал null, я либо генерирую исключение и обрабатываю его правильно, либо возвращаю пустой объект.
Если вы всегда ожидаете найти значение, бросьте исключение, если оно отсутствует. Исключение будет означать, что возникла проблема.
Если значение может отсутствовать или присутствовать и оба значения допустимы для логики приложения, верните значение NULL.
Более важно: что вы делаете в других местах кода? Последовательность важна.
@Ken: +1, было бы неплохо упомянуть, что если вы генерируете исключение, но можете обнаружить его априори (например, HasItem (...)), тогда пользователь должен предоставить указанный метод Has * или Contains.
Если вы выбрасываете исключения в методах модели, это заставляет разработчика разрабатывать блоки try / catch из вызывающей области, что гарантирует, что процедуры, вызывающие эти методы модели, обрабатываются должным образом из этой области. В противном случае разработчик мог делать все, что хотел. Если хотите, считайте это интерфейсом для вызова методов модели. Если данных нет, скорее всего, вам все равно придется найти обходной путь.
Вместо того, чтобы возвращать значение или ноль, когда значение отсутствует, рассмотрите возможность возврата Maybe <T>. См. mikehadlow.blogspot.nl/2011/01/monads-in-c-5-maybe.html.
В @ErwinRooijakkers способ выбора дизайна, начиная с Java 8, вы также можете вернуть Необязательно <T>
Перед лицом двусмысленности возникает соблазн выбрать один подход и последовательно придерживаться его. Я считаю, что мы должны хорошенько подумать, какой из них более уместен, и судить об этом в индивидуальном порядке. Контекстуально похожие случаи затем могут обрабатываться согласованным образом, и определение контекста выходит за рамки рассмотрения типов возвращаемых значений.
Меня это немного беспокоит, каждый ответ перекликается с одной и той же пословицей: «Если что-то особенное, брось». Большинство инженеров знакомы с этим принципом. На мой взгляд, реальный вопрос здесь в том, как определить, считается ли должно быть исключительным. OP ищет лучшая практика, например, в отношении чего-то вроде шаблона репозитория. Считается ли обычно исключительным, что объект не существует с данным первичным ключом? Да, это то, что будет определять его сфера деятельности, но что предлагают большинство экспертов с многолетним опытом? Вот какой ответ мы должны увидеть.
Кажется, это действительно вопрос личного мнения. Люди говорят о том, чтобы оставаться последовательными, но ответы здесь даже непоследовательны. Некоторые, кажется, думают, что это правильно, а другие думают, что вы должны вернуть null. И хотя проект вашей команды может оставаться последовательным, в тот момент, когда вы начнете использовать чужую библиотеку, вы можете столкнуться с несогласованностью, потому что не были определены четкие отраслевые требования для этого распространенного сценария. «Если значение может отсутствовать или присутствовать, и оба действительны ... вернуть ноль» Я бы добавил это с помощью Q, как следует определить, действительны ли оба?
@crush Я думаю, что руководящим принципом является какие параметры передаются функции. Если вы передаете личность, как вы упоминаете первичный ключ, то это следует считать исключительным, если этот элемент не найден, потому что указывает на несогласованное состояние в системе. Пример: GetPersonById(25) сгенерирует, если этот человек был удален, но GetPeopleByHairColor("red") вернет пустой результат. Итак, я думаю, что параметры что-то говорят об ожиданиях.
Последовательность важна!
Как правило, если метод всегда должен возвращать объект, используйте исключение. Если вы ожидаете случайного появления null и хотите обработать его определенным образом, используйте null.
Что бы вы ни делали, я настоятельно не рекомендую третий вариант: возвращать строку с надписью «WTF».
Плюс один, потому что в старые добрые времена я делал это более пары раз в качестве быстрого грязного «временного» исправления ... плохая идея. Особенно, если его собираются пересмотреть, если вы студент.
Я собирался проголосовать против, так как варианты WTF показались мне потрясающими ... но, видимо, у меня есть сердце
бросить новый WtfExcepti?n
Я думаю, было бы полезно, если бы в этом ответе говорилось о причинах, по которым метод всегда будет возвращать объект, а не «случайный нуль». Что оправдывает такую ситуацию? Приведите пример, когда может существовать такое обстоятельство.
Зависит от того, что означает, что объект не найден.
Если это нормальное состояние, верните null. Это просто то, что может происходить время от времени, и вызывающие абоненты должны это проверить.
Если это ошибка, то вызовите исключение, вызывающие должны решить, что делать с ошибочным состоянием отсутствия объекта.
В конечном итоге любой из них будет работать, хотя большинство людей обычно считают хорошей практикой использовать исключения только тогда, когда что-то, ну, исключительное произошло.
Как бы вы описали оператор «нормальное состояние дел» и какие критерии вы будете использовать, чтобы отличить его от ошибки.
Это зависит от характера метода и того, как он будет использоваться. Если это нормальное поведение, когда объект не может быть найден, верните 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.
На мой взгляд, лучший подход - попытка. Тогда вам не нужно искать, что произойдет, если объект не может быть возвращен. Используя метод Try, вы сразу знаете, что делать.
напоминает мне find и findOrFail из Laravel Eloquent
@ErikForbes Я знаю, что ваш комментарий старый, но разве не нужно было определить объект с несколькими свойствами, который будет возвращен методом TryFindObject? Кортежи кажутся более ленивой парадигмой для программистов, которые не хотят тратить время на определение объекта, который инкапсулирует несколько значений. По сути, все кортежи в любом случае лежат в основе.
@crush - Именованные литералы кортежей - это вариант, ИМО. Это ссылка на асинхронный шаблон Try Get с кортежами. stackoverflow.com/questions/1626597/…
Или верните вариант
Вариант - это, по сути, контейнерный класс, который заставляет клиента обрабатывать будки. У 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 - единственный значимый подход. Например, в параллельной карте / словаре нет способа спросить, будет ли отображение существовать, когда оно будет запрошено.
В некоторых функциях я добавляю параметр:
..., bool verify = true)
Истина означает выброс, ложь означает возврат некоторого возвращаемого значения ошибки. Таким образом, у того, кто использует эту функцию, есть оба варианта. Значение по умолчанию должно быть истинным для тех, кто забывает об обработке ошибок.
Отсутствие объекта может произойти во время обычных операций и должно быть обработано вызывающей стороной, возвращающей NULL.
Если объект не содержит, это указывает на ошибку вызывающим кодом или внутренним состоянием, тогда выполните assert.
Если объект не содержит, указывает на нечастое событие. (Подобно тому, как кто-то удалил элемент из магазина, в то время как вы одновременно извлекали этот элемент.) Затем создайте исключение.
Просто спросите себя: «Это исключительный случай, когда объект не найден»? Если ожидается, что это произойдет в ходе обычной работы вашей программы, вам, вероятно, не следует создавать исключение (поскольку это не исключительное поведение).
Краткая версия: используйте исключения для обработки исключительного поведения, а не для обработки обычного потока управления в вашей программе.
-Алан.
Исключения должны быть исключительный. Вернуть null если допустимо вернуть нуль.
Более-менее верно. См. boost.org/community/error_handling.html
Исключения связаны с проектированием по контракту.
Интерфейс объектов на самом деле является контрактом между двумя объектами, вызывающий должен соответствовать контракту, иначе получатель может просто выйти из строя с исключением. Возможны два контракта
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
Я просто хотел резюмировать варианты, упомянутые ранее, добавив несколько новых:
Или вы можете комбинировать эти варианты:
Предоставьте несколько перегруженных версий вашего геттера, чтобы вызывающая сторона могла решить, по какому пути идти. В большинстве случаев только первый из них реализует алгоритм поиска, а остальные просто охватывают первый:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Даже если вы решите предоставить только одну реализацию, вы можете использовать подобное соглашение об именах, чтобы прояснить свой контракт, и это поможет вам, если вы когда-нибудь решите добавить и другие реализации.
Вы не должны злоупотреблять им, но это может быть полезно, особенно при написании вспомогательного класса, который вы будете использовать в сотнях различных приложений с множеством различных соглашений об обработке ошибок.
Мне нравятся четкие имена функций, особенно orCreate и orDefault.
Большая часть этого может быть более четко написана с помощью Expected<T> findObject(String), где Expected<T> имеет функции orNull(), orThrow(), orSupplied(Supplier<T> supplier), orDefault(T default). Это абстрагирует получение данных от обработки ошибок.
До сих пор я не знал об Expected <T>. Кажется, я новичок и, возможно, не существовал, когда писал исходный ответ. Может быть, тебе стоит сделать свой комментарий правильным ответом.
Кроме того, Expected <T> - это шаблон C++. Есть ли его реализации на других объектно-ориентированных языках?
В Java 8 также возможен возврат Optional <T> (на других языках он называется Maybe <T> и т. д.). Это ясно указывает вызывающему, что возврат ничего не возможен и не будет компилироваться, если вызывающий не обработал эту возможность, в отличие от null, который (в любом случае в Java) будет компилироваться, даже если вызывающий его не проверит. .
имея в виду только случай, когда null не считается исключительным поведением, я определенно поддерживаю метод try, это ясно, нет необходимости «читать книгу» или «смотреть перед прыжком», как было сказано здесь
так в основном:
bool TryFindObject(RequestParam request, out ResponseParam response)
а это значит, что код пользователя тоже будет понятен
...
if (TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
Предпочитать возвращать null -
Если вызывающий использует его без проверки, исключение все равно произойдет прямо здесь.
Если вызывающий на самом деле не использует его, не облагайте его налогом блок try / catch.
К сожалению, JDK несовместим, если вы пытаетесь получить доступ к несуществующему ключу в пакете ресурсов, вы получаете исключение не найдено, и когда вы запрашиваете значение из карты, вы получаете null, если он не существует. Поэтому я бы изменил ответ победителя на следующий: если найденное значение может быть нулевым, затем вызвать исключение, если оно не найдено, в противном случае вернуть null. Поэтому следуйте правилу с одним исключением: если вам нужно знать, почему значение не найдено, всегда вызывайте исключение или ..
Преимущества выброса исключения:
Дополнительные объяснения с примерами см .: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
+1, потому что пункт 2 отличный - ноль не имеет того же значения, что и не найдено. Это становится более важным при работе с динамическими языками, где Null фактически может быть объектом, который хранится / извлекается функцией - и в этом случае
+1 за пункт №2. Нулевое значение является ошибкой? Имеет ли значение null то, что хранится для данного ключа? Нулевое значение указывает на то, что ключ не существует? Это настоящая цепочка вопросов, из которых ясно, что возвращение null почти никогда не бывает правильным. Это, вероятно, лучший ответ здесь, поскольку все остальные только что подбрасывали двусмысленное «Если это исключительное, бросайте»
Однако исключения могут привести к снижению производительности по сравнению с возвратами (например, в Java). И непроверенные исключения (например, в Java) могут появляться в непредусмотренных местах.
Если метод возвращает коллекцию, то верните пустую коллекцию (как сказано выше). Но, пожалуйста, не Collections.EMPTY_LIST или тому подобное! (в случае Java)
Если метод извлекает один объект, у вас есть несколько вариантов.
Будьте осторожны, если решите вернуть null. Если вы не единственный программист в проекте, вы получите NullPointerExceptions (на Java или на других языках) во время выполнения! Поэтому не возвращайте значения NULL, которые не проверяются во время компиляции.
Нет, если код был написан правильно, ожидая null. Подробнее см. В ответе, получившем наибольшее количество голосов.
Но только если вы убедитесь, что во время компиляции проверяются все значения NULL. Это можно сделать, используя FindBugs @NutNull на уровне пакета и пометив свой метод как «может возвращать null». Или использовать такой язык, как Kotlin или Nice. Но гораздо проще не возвращать null.
«Проще», может быть. Но часто совершенно неверно
Извините, но что не так, если метод, обещающий найти книгу, не может их найти и выдает исключение? Вы знаете "ошибку на миллиард долларов"? infoq.com/presentations/…
Еще раз: прочитайте ответ, получивший наибольшее количество голосов, для получения дополнительной информации. В основном: если это потенциально ожидаемый результат, что запрошенная книга не может быть найдена, исключение составляет действие неправильный, которое нужно сделать, когда запрошенная книга просто не найдена, в отличие от некоторой ошибки.
Ответ, получивший наибольшее количество голосов, не должен быть единственно правильным. Я не согласен с ответом. Также с этим не согласны Роберт С. Мартин (в книге «Чистый код: руководство по Agile Software Craftsmanshi») и Майкл Фезерс. А новые языки программирования, такие как Kotlin и Nice, подписываются на просмотр. И. Возможно, я слишком это принимаю близко к сердцу, но почему вы проголосовали против меня? Я не нарушал правила и мой ответ не так уж плох.
Вы здесь много неправильно понимаете. Вы применяете условный совет повсеместно, что почти всегда плохо. Прочтите также и остальные ответы, за которые проголосовали "за". Ваш ответ просто утверждает абсолют и представляет для него крайне ошибочную логику.
Я переписал ответ. Предыдущий ответ был только для Java.
Если вы используете библиотеку или другой класс, который генерирует исключение, вы должны перебросить его. Вот пример. 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' в выброшенное исключение.
Что бы вы ни делали, обязательно задокументируйте это. Я думаю, что этот момент более важен, чем какой именно подход является «лучшим».