У меня есть метод, который должен возвращать объект, если он найден.
Если он не найден, должен ли я:
- return null
- выполнить исключение
- другой
У меня есть метод, который должен возвращать объект, если он найден.
Если он не найден, должен ли я:
Если вы всегда ожидаете найти значение, то генерируйте исключение, если оно отсутствует. Исключение будет означать, что возникла проблема.
Если значение может отсутствовать или присутствовать, и оба действительны для логики приложения, то верните нуль.
Более важно: что вы делаете в другом месте в коде? Согласованность важна.
Выбрасывать исключение, только если это действительно ошибка. Если ожидается, что поведение объекта не будет существовать, верните нуль.
В противном случае это вопрос предпочтения.
Как правило, если метод всегда должен возвращать объект, перейдите к исключению. Если вы ожидаете случайный null и хотите обработать его определенным образом, перейдите к нулевому значению.
Независимо от того, что вы делаете, я настоятельно рекомендую третий вариант: Возврат строки с надписью "WTF".
Если значение null никогда не указывает на ошибку, просто верните значение null.
Если значение null всегда является ошибкой, выдайте исключение.
Если значение null иногда является исключением, тогда выполните два кода. Одна процедура генерирует исключение, а другая - логическая тестовая подпрограмма, которая возвращает объект в выходном параметре, и процедура возвращает false, если объект не был найден.
Трудно неправильно использовать процедуру Try. Очень легко забыть проверить нулевое значение.
Итак, когда null - это ошибка, вы просто пишете
object o = FindObject();
Когда значение null не является ошибкой, вы можете закодировать что-то вроде
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
Я просто хотел повторить описанные выше варианты, бросив несколько новых:
Или вы можете объединить эти параметры:
Предоставьте несколько перегруженных версий вашего геттера, чтобы вызывающий мог решить, куда идти. В большинстве случаев только первый имеет реализацию алгоритма поиска, а другие - только вокруг первого:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Даже если вы решите предоставить только одну реализацию, вы можете использовать соглашение об именах, подобное этому, чтобы уточнить свой контракт, и это поможет вам когда-либо решить добавить другие реализации.
Вы не должны злоупотреблять им, но это может быть полезно, особенно при написании вспомогательного класса, который вы будете использовать в сотнях различных приложений со многими различными соглашениями об обработке ошибок.
Используйте шаблон нулевого объекта или создайте исключение.
Будьте в согласии с API-интерфейсами, которые вы используете.
Это зависит от того, продвигается ли ваш язык и код: LBYL (смотрите, прежде чем прыгать) или EAFP (проще просить прощения, чем разрешение)
LBYL говорит, что вы должны проверить значения (так что верните нуль)
EAFP говорит просто попробовать операцию и посмотреть, не сработает ли она (выкинуть исключение)
хотя я согласен с выше. Исключения должны использоваться для исключительных/ошибок, а возврат нуль лучше всего при использовании проверок.
EAFP против LBYL в Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html
(Веб-архив)
Просто спросите себя: "Это исключительный случай, когда объект не найден"? Если ожидается, что это произойдет в обычном ходе вашей программы, вы, вероятно, не должны создавать исключение (поскольку это не исключительное поведение).
Краткая версия: используйте исключения для обработки исключительного поведения, а не для управления нормальным потоком управления в вашей программе.
-Alan.
Преимущества бросания исключения:
Более подробное объяснение с примерами см.: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
Исключения связаны с проектом по контракту.
Интерфейс объектов фактически является договором между двумя объектами, вызывающий должен соответствовать контракту, иначе получатель может просто потерпеть неудачу с исключением. Существует два возможных контракта
1) все введенные методы действительны, и в этом случае вы должны вернуть null, когда объект не найден.
2) допустим только некоторый ввод, т.е. тот, который приводит к найденному объекту. В этом случае вы ДОЛЖНЫ предложить второй метод, который позволяет вызывающему абоненту определить, будет ли его ввод корректным. Например
is_present(key)
find(key) throws Exception
ЕСЛИ И ТОЛЬКО ЕСЛИ вы предоставляете оба метода второго контракта, вам разрешено выкидывать исключение, ничего не найдено!
Я предпочитаю просто возвращать нуль и полагаться на вызывающего, чтобы обрабатывать его соответствующим образом. Исключение (из-за отсутствия лучшего слова) - это если я абсолютно "определен", этот метод вернет объект. В этом случае сбой является исключительным и должен бросить.
Зависит от того, что означает, что объект не найден.
Если это нормальное состояние дел, то верните нуль. Это как раз то, что может произойти раз в то время, и вызывающие должны проверить его.
Если это ошибка, то выкиньте исключение, вызывающие должны решить, что делать с условием ошибки отсутствующего объекта.
В конечном итоге либо будет работать, хотя большинство людей обычно считают хорошей практикой использовать Исключения только тогда, когда что-то, ну, Исключительное произошло.
Вот еще несколько советов.
Если вы возвращаете коллекцию, не возвращайте null, верните пустую коллекцию, которая позволяет проще перечислить нумерацию без нулевой проверки.
Несколько .NET API используют шаблон параметра thrownOnError, который дает выбору вызывающего объекта как исключительную ситуацию или нет, если объект не найден. Примером этого является Type.GetType. Другим распространенным шаблоном с BCL является шаблон TryGet, в котором возвращается логическое значение, и значение передается через выходной параметр.
Вы также можете рассмотреть шаблон Null Object в некоторых случаях, который может быть либо по умолчанию, либо версией без какого-либо поведения. Ключ избегает нулевых проверок на всей базе кода. См. Здесь для получения дополнительной информации http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
Возвращает нуль вместо того, чтобы бросать исключение и четко документировать возможность возвращаемого значения null в документации API. Если вызывающий код не соблюдает API и не проверяет нулевой регистр, скорее всего, это приведет к некоторому "исключению нулевого указателя":)
В С++ я могу думать о трех разных вариантах настройки метода, который находит объект.
Вариант A
Object *findObject(Key &key);
Возвращает значение null, когда объект не может быть найден. Ницца и просто. Я бы пошел с этим. Альтернативные подходы ниже для тех, кто не ненавидит out-params.
Вариант B
void findObject(Key &key, Object &found);
Передайте ссылку на переменную, которая будет получать объект. Метод генерирует исключение, когда объект не может быть найден. Это соглашение, вероятно, более подходит, если на самом деле не ожидается, что объект не будет найден - поэтому вы делаете исключение, чтобы показать, что это неожиданный случай.
Вариант C
bool findObject(Key &key, Object &found);
Метод возвращает false, когда объект не может быть найден. Преимущество этого над вариантом A состоит в том, что вы можете проверить наличие ошибки на одном ясном шаге:
if (!findObject(myKey, myObj)) { ...
В некоторых функциях я добавляю параметр:
..., bool verify = true)
True означает, что throw, false означает возврат некоторого значения возврата ошибки. Таким образом, тот, кто использует эту функцию, имеет оба варианта. Значение по умолчанию должно быть истинным, в интересах тех, кто забывает об обработке ошибок.
ссылаясь только на случай, когда 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 должен быть хорошим.
Однако, если он возвращает всю чертову вещь (например, на С++, если вы делаете: "return blah", а не "return & blah;" (или "blah" - это указатель), вы не можете вернуть NULL, потому что это не тип "объект". В этом случае, бросая исключение или возвращая пустой объект, у которого нет установленного флажка успеха, я хотел бы подойти к проблеме.
Не думайте, что кто-то упомянул об избыточных затратах на обработку исключений - требует дополнительных ресурсов для загрузки и обработки исключения, поэтому, если его истинное событие, связанное с убийством или прекращением процесса (в будущем это принесет больше вреда, чем пользы), я бы выбрал передавая значение, которое вызывающая среда может интерпретировать по своему усмотрению.
Я согласен с тем, что кажется консенсусом здесь (возврат null, если "не найден" является нормальным возможным результатом, или генерирует исключение, если для семантики ситуации требуется, чтобы объект всегда был найден).
Существует, однако, третья возможность, которая может иметь смысл в зависимости от вашей конкретной ситуации. Ваш метод может вернуть объект по умолчанию в состоянии "не найден", позволяя коду-коду быть уверенным, что он всегда будет получать действительный объект без необходимости проверки нуля или исключения catch.
Возвращает нуль, исключения - это именно то, чего не делает ваш код.
Исключения должны быть исключительными. Верните null , если он верен для возврата null.
Предпочитает возвращение null -
Если вызывающий абонент использует его без проверки, исключение происходит в любом случае.
Если вызывающий абонент действительно не использует его, не налагайте ему налог try
/catch
block
К сожалению, JDK несовместим, если вы пытаетесь получить доступ к не существующему ключу в наборе ресурсов, вы не получаете исключение, и когда вы запрашиваете значение из карты, вы получаете null, если он не существует. Поэтому я бы изменил ответ победителя на следующий, если найденное значение может быть нулевым, а затем повысить исключение, если оно не найдено, в противном случае возвращает null. Поэтому следуйте правилу с одним исключением, если вам нужно знать, почему значение не найдено, всегда поднимайте исключение или...
Если метод возвращает коллекцию, верните пустую коллекцию (как сказано выше). Но, пожалуйста, не Collections.EMPTY_LIST или такой! (в случае Java)
Если метод возвращает один объект, у вас есть некоторые параметры.
Будьте осторожны, если вы решите вернуть нуль. Если вы не единственный программист в проекте, вы получите NullPointerExceptions (на 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\"");
}
}
Это действительно зависит от того, хотите ли вы найти объект или нет. Если вы следуете школе мысли о том, что исключения должны использоваться для указания чего-то, ну, ошибка, исключительная произошла тогда:
В противном случае верните null.