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

StackOverflow https://stackoverflow.com/questions/175532

  •  05-07-2019
  •  | 
  •  

Вопрос

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

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

  1. возвращает значение null
  2. создать исключение
  3. Другое
Это было полезно?

Решение

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

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

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

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

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

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

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

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

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

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

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

Трудно неправильно использовать процедуру Try. Это действительно легко забыть проверить на ноль.

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

object o = FindObject();

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

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 ( Веб-архив )

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

    <Ол>
  • Очистите поток управления в вызывающем коде. Проверка на нулевое значение вводит условную ветвь, которая изначально обрабатывается try / catch. Проверка на нулевое значение не указывает на то, что вы проверяете - проверяете ли вы на нулевое значение, потому что ищете ожидаемую ошибку, или проверяете на нулевое значение, чтобы не передавать ее дальше по нисходящей цепи ?
  • Устраняет неоднозначность того, что " null " означает. является нулевым представителем ошибки или является нулевым, что на самом деле хранится в значении? Трудно сказать, когда у вас есть только одна вещь, чтобы обосновать это определение.
  • Улучшенная согласованность между поведением методов в приложении. Исключения обычно отображаются в сигнатурах методов, чтобы вы могли лучше понять, для каких крайних случаев используются методы в учетной записи приложения, и какую информацию приложение может реагировать на предсказуемый характер.
  • Дополнительные пояснения с примерами см. на странице http : //metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/

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

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

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

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

    is_present(key)
    find(key) throws Exception
    

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

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

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

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

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

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

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

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

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

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

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

    ..., bool verify = true)
    

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

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

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

    Вариант A

    Object *findObject(Key &key);
    

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

    Вариант B

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

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

    Вариант C

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

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

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

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

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

    bool TryFindObject(RequestParam request, out ResponseParam response)
    

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Предпочитаю возвращать ноль -

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

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

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

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

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

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

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top