Я использую язык Java, у меня есть метод, который должен возвращать объект, если он найден.
Если он не найден, я должен:
- вернуть ноль
- выбросить исключение
- разное
Что лучше всего или идиома?
Я использую язык Java, у меня есть метод, который должен возвращать объект, если он найден.
Если он не найден, я должен:
Что лучше всего или идиома?
Если вы всегда ожидаете найти значение, тогда вызовите исключение, если оно отсутствует. Исключение будет означать, что возникла проблема.
Если значение может отсутствовать или присутствовать, и оба значения допустимы для логики приложения, верните значение NULL.
Более важно: что вы делаете в других местах кода? Последовательность важна.
Выбрасывайте исключение только в том случае, если это действительно ошибка. Если ожидается, что объект не существует, верните значение null.
В противном случае это вопрос предпочтения.
Как правило, если метод всегда должен возвращать объект, используйте исключение. Если вы ожидаете случайного появления null и хотите обработать его определенным образом, используйте null.
Что бы вы ни делали, я настоятельно не рекомендую третий вариант: возвращать строку с надписью «WTF».
Если null никогда не указывает на ошибку, просто верните null.
Если значение null всегда является ошибкой, вызовите исключение.
Если null иногда является исключением, запрограммируйте две процедуры. Одна процедура выдает исключение, а другая - это логическая тестовая процедура, которая возвращает объект в выходном параметре, а процедура возвращает ложь, если объект не был найден.
Трудно злоупотребить рутиной Try. Очень легко забыть проверить значение null.
Поэтому, когда null является ошибкой, вы просто пишете
object o = FindObject();
Если нуль не является ошибкой, вы можете написать что-то вроде
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
find
и findOrFail
из Laravel Eloquent 31.05.2018 TryFindObject
? Кортежи кажутся более ленивой парадигмой для программистов, которые не хотят тратить время на определение объекта, который инкапсулирует несколько значений. По сути, все кортежи в любом случае лежат в основе. 09.08.2018 Я просто хотел резюмировать варианты, упомянутые ранее, добавив несколько новых:
Или вы можете комбинировать эти варианты:
Предоставьте несколько перегруженных версий вашего геттера, чтобы вызывающая сторона могла решить, по какому пути идти. В большинстве случаев только первый из них реализует алгоритм поиска, а остальные просто охватывают первый:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Даже если вы решите предоставить только одну реализацию, вы можете использовать подобное соглашение об именах, чтобы прояснить свой контракт, и это поможет вам, если вы когда-нибудь решите добавить и другие реализации.
Вы не должны злоупотреблять им, но это может быть полезно, особенно при написании вспомогательного класса, который вы будете использовать в сотнях различных приложений с множеством различных соглашений об обработке ошибок.
Expected<T> findObject(String)
, где Expected<T>
имеет функции orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. Это абстрагирует получение данных от обработки ошибок. 06.10.2015 Используйте шаблон нулевого объекта или создайте исключение.
Person somePerson = personRepository.find("does-not-exist");
Предположим, этот метод возвращает нулевой объект для ID does-not-exist
. Каким же тогда было бы правильное поведение для somePerson.getAge()
? Прямо сейчас я еще не убежден, что шаблон нулевого объекта - правильное решение для поиска сущностей. 15.06.2015 NullRecord
, весь код, который пытается прочитать массив, должен был бы преобразовать ссылку RecordBase
в ссылку RealRecord
, что не удалось бы, если элемент на самом деле является NullRecord
, а я не не вижу, что можно было бы получить. 26.04.2020 T[]
с произвольным универсальным типом T
, разрешите чтение элементов в тех случаях, когда не может быть статически доказано, что они были написаны, и определите поведение такого чтения, то он должен определить состояние по умолчанию для элементов массива, которые еще не были записаны. C # предоставляет унифицированный синтаксис для ссылки на значение по умолчанию любого произвольного T
; для ссылочных типов возвращается значение null; для числовых типов - ноль; для типов структуры он дает структуру со всеми полями, содержащими значения по умолчанию. 26.04.2020 Будьте совместимы с API, которые вы используете.
Просто спросите себя: «Это исключительный случай, когда объект не найден»? Если ожидается, что это произойдет в ходе обычной работы вашей программы, вам, вероятно, не следует создавать исключение (поскольку это не исключительное поведение).
Краткая версия: используйте исключения для обработки исключительного поведения, а не для обработки обычного потока управления в вашей программе.
-Алан.
Преимущества выброса исключения:
Дополнительные объяснения с примерами см .: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
это зависит от того, поддерживает ли ваш язык и код: LBYL (посмотрите, прежде чем прыгать) или EAFP (проще попросить прощения, чем разрешения)
LBYL говорит, что вы должны проверять значения (так что возвращайте ноль)
EAFP предлагает просто попробовать операцию и посмотреть, не удастся ли она (выбросить исключение)
хотя я согласен с вышеизложенным ... исключения должны использоваться для исключительных условий / условий ошибки, а возврат null лучше всего при использовании проверок.
EAFP против LBYL в Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html (Веб-архив)
Исключения связаны с проектированием по контракту.
Интерфейс объектов на самом деле является контрактом между двумя объектами, вызывающий должен соответствовать контракту, иначе получатель может просто выйти из строя с исключением. Возможны два контракта
1) все входные данные метода действительны, и в этом случае вы должны вернуть null, если объект не найден.
2) действителен только некоторый ввод, то есть тот, который приводит к найденному объекту. В этом случае вы ДОЛЖНЫ предложить второй метод, который позволяет вызывающему абоненту определить, будет ли его ввод правильным. Например
is_present(key)
find(key) throws Exception
ЕСЛИ и ТОЛЬКО ЕСЛИ вы предоставляете оба метода 2-го контракта, вам разрешено генерировать исключение, ничего не найдено!
Зависит от того, что означает, что объект не найден.
Если это нормальное состояние, верните null. Это просто то, что может происходить время от времени, и вызывающие абоненты должны это проверить.
Если это ошибка, то вызовите исключение, вызывающие должны решить, что делать с ошибочным состоянием отсутствия объекта.
В конечном итоге любой из них будет работать, хотя большинство людей обычно считают хорошей практикой использовать исключения только тогда, когда что-то, ну, исключительное произошло.
Вот еще пара предложений.
При возврате коллекции избегайте возврата null, возвращайте пустую коллекцию, которая упрощает работу с перечислением без предварительной проверки на null.
Некоторые API .NET используют шаблон параметра thrownOnError, который дает вызывающей стороне выбор, действительно ли это исключительная ситуация или нет, если объект не найден. Type.GetType является примером этого. Другой распространенный шаблон с BCL - это шаблон TryGet, в котором возвращается логическое значение, а значение передается через выходной параметр.
В некоторых случаях вы также можете рассмотреть шаблон «Нулевой объект», который может быть либо значением по умолчанию, либо версией без поведения. Ключ в том, чтобы избегать нулевых проверок по всей базе кода. Дополнительную информацию см. Здесь http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
Я предпочитаю просто возвращать значение NULL и полагаюсь на то, что вызывающий объект обработает его должным образом. Исключение (из-за отсутствия лучшего слова) - это если я абсолютно уверен, что этот метод вернет объект. В этом случае отказ является исключительным случаем, который должен и должен бросить.
В некоторых функциях я добавляю параметр:
..., bool verify = true)
Истина означает выброс, ложь означает возврат некоторого возвращаемого значения ошибки. Таким образом, у любого, кто использует эту функцию, есть оба варианта. Значение по умолчанию должно быть истинным для тех, кто забывает об обработке ошибок.
Верните значение NULL вместо создания исключения и четко задокументируйте возможность возврата значения NULL в документации по API. Если вызывающий код не соблюдает API и не проверяет регистр NULL, это, скорее всего, все равно приведет к некоему «исключению с нулевым указателем» :)
В C ++ я могу придумать 3 различных варианта настройки метода, который находит объект.
Вариант А
Object *findObject(Key &key);
Возвращает null, если объект не может быть найден. Красиво и просто. Я бы пошел с этим. Приведенные ниже альтернативные подходы предназначены для людей, которые не ненавидят out-params.
Вариант Б
void findObject(Key &key, Object &found);
Передайте ссылку на переменную, которая будет получать объект. Метод вызвал исключение, когда объект не может быть найден. Это соглашение, вероятно, более подходит, если на самом деле не ожидается, что объект не будет найден - следовательно, вы генерируете исключение, чтобы указать, что это неожиданный случай.
Вариант В
bool findObject(Key &key, Object &found);
Метод возвращает false, если объект не может быть найден. Преимущество этого варианта перед вариантом A заключается в том, что вы можете проверить случай ошибки за один четкий шаг:
if (!findObject(myKey, myObj)) { ...
имея в виду только случай, когда null не считается исключительным поведением, я определенно поддерживаю метод try, это ясно, нет необходимости «читать книгу» или «смотреть перед прыжком», как было сказано здесь
так в основном:
bool TryFindObject(RequestParam request, out ResponseParam response)
а это значит, что код пользователя тоже будет понятен
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
Если клиентскому коду важно знать разницу между найденным и не найденным, и это должно быть обычным поведением, тогда лучше вернуть null. Затем клиентский код может решить, что делать.
Обычно он должен возвращать null. Код, вызывающий метод, должен решить, выбросить ли исключение или попытаться сделать что-то еще.
Или вернуть вариант
Вариант - это, по сути, контейнерный класс, который заставляет клиента обрабатывать будки. У Scala есть такая концепция, посмотрите ее API.
Затем у вас есть такие методы, как T getOrElse (T valueIfNull) для этого объекта, которые либо возвращают найденный объект, либо все альтернативы, указанные клиентом.
Предпочитать возвращать null -
Если вызывающий использует его без проверки, исключение все равно произойдет прямо здесь.
Если вызывающий на самом деле не использует его, не облагайте его налогом _1 _ / _ 2_ блок
К сожалению, JDK несовместим, если вы пытаетесь получить доступ к несуществующему ключу в пакете ресурсов, вы получаете исключение не найдено, и когда вы запрашиваете значение из карты, вы получаете null, если он не существует. Итак, я бы изменил ответ победителя на следующий: если найденное значение может быть нулевым, затем вызвать исключение, если оно не найдено, в противном случае вернуть null. Поэтому следуйте правилу с одним исключением: если вам нужно знать, почему значение не найдено, всегда вызывайте исключение или ..
Если предполагается, что он возвращает ссылку на объект, возвращение NULL должно быть нормальным.
Однако, если он возвращает всю чертову штуку (как в C ++, если вы это делаете: 'return blah;' вместо 'return' (или 'blah' - указатель), то вы не можете вернуть NULL, потому что это не введите "объект". В этом случае я бы подошел к проблеме, выбрасывая исключение или возвращая пустой объект, для которого не установлен флаг успеха.
Не думайте, что кто-то упомянул накладные расходы при обработке исключений - требуются дополнительные ресурсы для загрузки и обработки исключения, поэтому, если это не настоящее событие, связанное с убийством приложения или остановкой процесса (дальнейшее продвижение принесет больше вреда, чем пользы), я бы предпочел передать обратно Ценность вызывающей среды может интерпретировать так, как считает нужным.
Я согласен с тем, что кажется здесь консенсусом (возврат null, если «не найден» является нормальным возможным результатом, или выбросить исключение, если семантика ситуации требует, чтобы объект всегда был найден).
Однако существует третья возможность, которая может иметь смысл в зависимости от вашей конкретной ситуации. Ваш метод может вернуть какой-либо объект по умолчанию в состоянии «не найден», что позволяет вызывающему коду быть уверенным, что он всегда получит действительный объект без необходимости проверки на null или перехвата исключений.
Верните нулевое значение, исключения - это именно то, что: ваш код делает то, чего не ожидают.
Исключения должны быть исключительными. Верните ноль , если допустимо вернуть ноль.
Если метод возвращает коллекцию, то верните пустую коллекцию (как сказано выше). Но, пожалуйста, не Collections.EMPTY_LIST или тому подобное! (в случае Java)
Если метод извлекает один объект, у вас есть несколько вариантов.
Будьте осторожны, если решите вернуть нуль. Если вы не единственный программист в проекте, вы получите NullPointerExceptions (на Java или на других языках) во время выполнения! Поэтому не возвращайте значения NULL, которые не проверяются во время компиляции.
null
. Подробнее см. В ответе, получившем наибольшее количество голосов. 21.08.2012 Если вы используете библиотеку или другой класс, который вызывает исключение, вам следует повторно выбросить его. Вот пример. 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\"");
}
}
Это действительно зависит от того, ожидаете ли вы найти объект или нет. Если вы следите за школой мысли, что исключения следует использовать для обозначения чего-то, ну, эээ, тогда произошло исключение:
В противном случае верните null.
Это зависит от характера метода и от того, как он будет использоваться. Если это нормальное поведение, когда объект не может быть найден, верните null. Если объект всегда найден, это нормальное поведение, генерировать исключение.
Как правило, используйте исключения только тогда, когда что-то исключительное происходит. Не пишите код таким образом, чтобы генерация и перехват исключений была частью его нормальной работы.
Если не обнаружено, что это исключительное событие (т.е. оно должно быть там при нормальных обстоятельствах), бросьте. В противном случае верните значение «не найдено» (может быть нулевым, но не обязательно) или даже пусть метод возвращает логическое значение для найденного / не найденного и параметр out для фактического объекта.
Это зависит от вашего метода. Если ваш метод должен всегда возвращать действительный объект, и ни один из них не найден, можно использовать исключение. Если метод просто возвращает объект, который может быть, а может и не быть (например, изображение контактного лица), вы не должны выдавать ошибку.
Вы также можете открыть метод, возвращающий логическое значение true / false, если этот метод действительно возвращает объект, поэтому вам не нужно: а) проверять значение 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.
Если объект не содержит, это указывает на ошибку вызывающим кодом или внутренним состоянием, тогда выполните assert.
Если объект не содержит, указывает на нечастое событие. (Как будто кто-то удалил элемент из магазина, в то время как вы одновременно извлекали этот элемент.) Затем создайте исключение.
GetPersonById(25)
будет сгенерирован, если этот человек был удален, ноGetPeopleByHairColor("red")
вернет пустой результат. Итак, я думаю, что параметры что-то говорят об ожиданиях. 01.11.2018