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

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

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

  • return null
  • выполнить исключение
  • другой

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

Независимо от того, что вы делаете, я настоятельно рекомендую третий вариант: Возврат строки с надписью "WTF".

Ответ 4

Если значение 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

Ответ 5

Я просто хотел повторить описанные выше варианты, бросив несколько новых:

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

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

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

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

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

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

Ответ 6

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

Ответ 7

Будьте в согласии с API-интерфейсами, которые вы используете.

Ответ 8

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

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

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


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

Ответ 9

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

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

-Alan.

Ответ 10

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

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

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

Ответ 11

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

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

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

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

is_present(key)
find(key) throws Exception

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

Ответ 12

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

Ответ 13

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

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

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

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

Ответ 14

Вот еще несколько советов.

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

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

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

Ответ 15

Возвращает нуль вместо того, чтобы бросать исключение и четко документировать возможность возвращаемого значения 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)) { ...

Ответ 16

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

..., bool verify = true)

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

Ответ 17

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

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

bool TryFindObject(RequestParam request, out ResponseParam response)

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

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

Ответ 18

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

Ответ 19

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

Ответ 20

Или верните опцию

Опция - это в основном контейнерный класс, который заставляет клиента обрабатывать шкафы. Scala имеет эту концепцию, посмотрите ее API.

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

Ответ 21

Пока он должен возвращать ссылку на объект, возврат NULL должен быть хорошим.

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

Ответ 22

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

Ответ 23

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

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

Ответ 24

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

Ответ 25

Исключения должны быть исключительными. Верните null , если он верен для возврата null.

Ответ 26

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

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

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

Ответ 27

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

Ответ 28

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

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

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

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

Ответ 29

Если вы используете библиотеку или другой класс, который генерирует исключение, вы должны ретронировать. Вот пример. 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\"");
    }

}

Ответ 30

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

  • Объект найден; return object
  • Объект не найден; исключение исключения

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