Подтвердить что ты не робот

Возвращает нулевой плохой дизайн?

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

псевдокод:

variable x = object.method()
if (x is null) do something
4b9b3361

Ответ 1

Обоснование отсутствия возвращаемого значения null заключается в том, что вам не нужно проверять его, и, следовательно, вашему коду не требуется следовать другому пути на основе возвращаемого значения. Возможно, вы захотите проверить Null Object Pattern, в котором содержится дополнительная информация об этом.

Например, если бы я должен был определить метод в Java, который возвращал коллекцию, я обычно предпочитал бы возвращать пустую коллекцию (т.е. Collections.emptyList()), а не null, поскольку это означает, что мой клиентский код более чист; например.

Collection<? extends Item> c = getItems(); // Will never return null.

for (Item item : c) { // Will not enter the loop if c is empty.
  // Process item.
}

... который чище, чем:

Collection<? extends Item> c = getItems(); // Could potentially return null.

// Two possible code paths now so harder to test.
if (c != null) {
  for (Item item : c) {
    // Process item.
  }
}

Ответ 2

Вот причина.

В "Чистый код" Роберта Мартина он пишет, что возврат нулевого значения - это плохой дизайн, когда вы можете вместо этого вернуть, скажем, пустой массив. Поскольку ожидаемый результат - это массив, почему бы и нет? Это позволит вам перебирать результат без каких-либо дополнительных условий. Если это целое число, возможно, 0 будет достаточно, если это хэш, пустой хеш. и др.

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

Ответ 3

Хорошее использование возвращаемого значения null:

  • Если null является допустимым функциональным результатом, например: FindFirstObjectThatNeedsProcessing() может возвращать null, если не найден, и вызывающий должен проверить соответствующим образом.

Плохое использование: попытка заменить или скрыть исключительные ситуации, такие как:

  • catch (...) и возврат null
  • Ошибка инициализации зависимостей API
  • Вне дискового пространства
  • Недействительные входные параметры (ошибка программирования, входные данные должны быть дезинфицированы вызывающим абонентом)
  • и т.д.

В тех случаях бросание исключения является более адекватным, поскольку:

  • Значение возвращаемого значения null не содержит значимой информации об ошибке
  • Непосредственный вызывающий абонент, скорее всего, не сможет обработать условие ошибки
  • Нет гарантии, что вызывающий абонент проверяет нулевые результаты

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

  • Неверное имя пользователя/пароль (или любые введенные пользователем входы)
  • Ломающиеся циклы или как нелокальные gotos

Ответ 4

Да, возвращение NULL - ужасный дизайн в объектно-ориентированном мире. Вкратце, использование NULL приводит к:

  • ad-hoc обработка ошибок (вместо исключений)
  • двусмысленный семантический
  • медленный, а не быстрый
  • компьютерное мышление вместо объектного мышления
  • изменчивые и неполные объекты

Проверьте это сообщение в блоге для подробного объяснения: http://www.yegor256.com/2014/05/13/why-null-is-bad.html. Больше в моей книге " Элегантные объекты", раздел 4.1.

Ответ 5

Кто сказал, что это плохой дизайн?

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

Ответ 6

Основываясь на том, что вы сказали до сих пор, я думаю, что информации недостаточно.

Возврат null из метода CreateWidget() кажется плохим.

Возврат null из метода FindFooInBar() кажется прекрасным.

Ответ 7

Его изобретатель говорит, что это ошибка в миллиард долларов!

Ответ 8

Это зависит от языка, который вы используете. Если у вас такой язык, как С#, где идиоматический способ указывать на отсутствие значения - это вернуть значение null, то возврат нулевого значения является хорошим дизайном, если у вас нет значения. В качестве альтернативы, в таких языках, как Haskell, которые идиоматически используют монадию Maybe для этого случая, то возврат null будет плохим дизайном (если бы это было возможно).

Ответ 9

Если вы прочтете все ответы, становится ясно, что ответ на этот вопрос зависит от метода.

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

Всякий раз, когда ожидается, что метод не будет иметь никаких результатов, существуют две категории:

  • Если можно вернуть нейтральное значение, сделайте это.
    Пустые списки, строки и т.д. Являются хорошими примерами.
  • Если такое нейтральное значение не существует, null должен быть возвращен.
    Как уже упоминалось, предполагается, что этот метод не имеет результата, поэтому он не является исключительным, поэтому не должен генерировать исключение. Нейтральное значение невозможно (например: 0 не является особенно нейтральным результатом, в зависимости от программы)

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

Я еще не совсем в порядке с именем, но не мог придумать ничего лучшего. Так что я бегу с этим пока.

Ответ 10

Прекрасно возвращать значение null, если это имеет смысл в некотором роде:

public String getEmployeeName(int id){ ..}

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

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

public Integer getId(...){
   try{ ... ; return id; }
   catch(Exception e){ return null;}
}

Ответ 11

Это не обязательно плохой дизайн - как и во многих дизайнерских решениях, это зависит.

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

object x = GetObjectFromCache();   // return null if it not in the cache

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

try {
   Controller c = GetController();    // the controller object is central to 
                                      //   the application. If we don't get one, 
                                      //   we're fubar

   // it likely that it OK to not have the try/catch since you won't 
   // be able to really handle the problem here
}
catch /* ... */ {
}

Ответ 12

Исключения для исключений всех обстоятельств.

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

Ответ 13

У меня есть соглашение в этой области, которое хорошо меня обслуживало

Для запросов отдельных элементов:

  • Create... возвращает новый экземпляр или бросает
  • Get... возвращает ожидаемый существующий экземпляр или бросает
  • GetOrCreate... возвращает существующий экземпляр или новый экземпляр, если он не существует, или выбрасывает
  • Find... возвращает существующий экземпляр, если он существует, или null

Для запросов на сбор:

  • Get... всегда возвращает коллекцию, которая пуста, если не найдено соответствующих [1] элементов

[1] заданы некоторые критерии, явные или неявные, заданные в имени функции или как параметры.

Ответ 14

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

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

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

Ответ 15

Какие альтернативы вы видите для возврата null?

Я вижу два случая:

  • findAnItem (id). Что делать, если элемент не найден.

В этом случае мы могли бы: вернуть Null или выбросить исключение (отмеченное) (или, возможно, создать элемент и вернуть его)

  • listItemsMatching (критерии), что это должно вернуть, если ничего не найдено?

В этом случае мы можем вернуть Null, вернуть пустой список или выбросить исключение.

Я считаю, что возврат null может быть менее хорошим, чем альтернативы, потому что он требует, чтобы клиент помнил, чтобы проверить значение null, программисты забывают и кодируют

x = find();
x.getField();  // bang null pointer exception

В Java, бросая проверенное исключение, RecordNotFoundException, позволяет компилятору напомнить клиенту о том, чтобы иметь дело с случаем.

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

Ответ 16

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

Ответ 17

Заставьте их вызвать другой метод после факта, чтобы выяснить, был ли предыдущий вызов нулевым.;-) Эй, это было достаточно хорошо для JDBC

Ответ 18

Основная идея этого потока - запрограммировать защиту. То есть, код против неожиданного. Существует множество ответов:

Adamski предлагает посмотреть на шаблон Null Object Pattern, причем этот ответ будет проголосован за это предложение.

Michael Valenty также предлагает соглашение об именах, чтобы сообщить разработчику, что можно ожидать. ZeroConcept предлагает правильное использование Exception, если это причина NULL. И другие.

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

Но у нас есть 2 сценария разработки.

Классы, "разработанные" разработчиком: Автор

Классы, "потребляемые" другим (возможно) разработчиком: Разработчик

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

Если разработчик не может этого сделать, то этот класс/метод не является детерминированным. То есть, если "вызов метода" для получения объекта не выполняет то, что он "рекламирует" (например, getEmployee), он нарушил контракт.

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

Таким образом, при условии, что необходимо указать NULL или NULL OBJECT (например, если (сотрудник как NullEmployee.ISVALID)) и это может потребоваться с коллекцией сотрудников, тогда подход с нулевым объектом является лучшим подходом.

Но мне также нравится предложение Michael Valenty's именования метода, который ДОЛЖЕН возвращать null, например getEmployeeOrNull.

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

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

Так как разработчик, я бы запрограммировал защиту против NULL из метода. Если автор дал мне контракт, который всегда возвращает объект (всегда имеет значение NULL OBJECT) и этот объект имеет метод/свойство, с помощью которого можно проверить достоверность объекта, то я бы использовал этот метод/свойство для продолжения использования объекта, иначе объект недействителен и я не могу его использовать.

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

Разработчик должен всегда использовать защитное программирование для проверки достоверности возвращаемых объектов из другого класса/метода.

приветствует

GregJF

Ответ 19

Другими вариантами этого являются: возвращая некоторое значение, которое указывает на успех или нет (или тип ошибки), но если вам просто нужно логическое значение, которое будет указывать на успех/неудачу, возвращая значение null для отказа, а объект для успеха будет не менее корректным, а затем вернется true/false и получение объекта через параметр.
Другой подход заключался бы в том, чтобы использовать исключение для обозначения сбоев, но здесь - на самом деле существует гораздо больше голосов, которые говорят, что это практическая практика (поскольку использование исключений может быть удобным, но имеет множество недостатков). Поэтому я лично не вижу ничего плохого в возвращении null как признаке того, что что-то пошло не так, и проверив его позже (чтобы действительно знать, преуспели вы или нет). Кроме того, слепо думая, что ваш метод не вернет NULL, а затем основать ваш код на нем, может привести к другим, иногда трудно найти, ошибкам (хотя в большинстве случаев это просто приведет к краху вашей системы:), поскольку вы ссылаетесь на 0x00000000 рано или поздно).

Ответ 20

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

Нулевая функция или метод часто используются в качестве поведения по умолчанию для переопределяемой функции или переопределяемого метода в рамках объекта.

Null_function @wikipedia

Ответ 21

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

Ответ 22

Если код выглядит примерно так:

command = get_something_to_do()

if command:  # if not Null
    command.execute()

Если у вас есть фиктивный объект, метод execute() ничего не делает, и вы возвращаете это вместо Null в соответствующих случаях, вам не нужно проверять нулевой регистр и вместо этого просто делать:

get_something_to_do().execute()

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

Ответ 23

Для моего случая использования мне нужно было вернуть Map из метода, а затем найти конкретный ключ. Но если я верну пустую карту, это приведет к исключению NullPointerException, и тогда это не будет сильно отличаться, возвращая null вместо пустой карты. Но из Java8 дальше мы могли бы использовать Факультативно. Вышесказанное является той самой причиной, по которой была введена дополнительная концепция.

Ответ 24

G'day,

Возвращение NULL, когда вы не можете создать новый объект, является стандартной практикой для многих API.

Почему, черт возьми, это плохой дизайн, я понятия не имею.

Изменить: Это относится к языкам, на которых у вас нет исключений, таких как C, где это соглашение уже много лет.

НТН

'Avahappy,