Лучше ли возвращать NULL или пустые значения из функций / методов, где возвращаемое значение отсутствует?

135

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

Возьмите следующие два метода в качестве примера:

string ReverseString(string stringToReverse) // takes a string and reverses it.
Person FindPerson(int personID)    // finds a Person with a matching personID.

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

В FindPerson(), возвращая NULL кажется лучшей подгонки. Независимо от того, new Person()возвращен ли NULL или пустой объект Person ( ), вызывающая сторона должна будет проверить, является ли объект Person пустым или пустым, прежде чем что-либо с ним делать (например, вызывать UpdateName()). Так почему бы просто не вернуть NULL здесь, и тогда вызывающая сторона должна только проверить NULL.

Кто-нибудь еще борется с этим? Любая помощь или понимание приветствуется.

PB
источник
2
Это будет меняться. Вы также можете утверждать, что метод должен останавливать значения, которые являются неверными, например, ваш параметр stringToReverse передается как пустой или нулевой. Если вы выполнили эту проверку (вернули исключение), она всегда будет возвращать что-то отличное от нуля.
Аарон Макивер
Фаулер POEAA - с. 496 Базовые паттерны - особый случай (нулевой объект) Bloch Effective Java, 2nd Edition Item 43: Возвращать пустые массивы или коллекции, а не нули
Борис Треухов
1
@ Борис Я не видел твой комментарий. Я на самом деле только что опубликовал Special Case в качестве ответа.
Томас Оуэнс
@ Томас Я не вижу в этом никакой проблемы :). Что касается вопроса, это все равно вопрос здравого смысла.
Борис Треухов
Интересный комментарий заключается в том, что в базах данных Oracle значения NULL и пустая строка совпадают
WuHoUnited

Ответы:

77

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

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

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

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

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

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

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

JW8
источник
8
Лично мне нравится возвращать пустые строки для функций, которые возвращают строки, чтобы минимизировать объем обработки ошибок, который необходимо ввести в действие. Никогда не понимал этот аргумент. Нулевая проверка - что, самое большее <10 символов? Почему мы ведем себя так, будто это снова изгиб?
Аарон Макивер
19
Никто не сказал, что это снова изгиб. Но это труд. Он добавляет специальный код в код, который означает еще одну ветвь для тестирования. Кроме того, это нарушает поток кода. for x in list_of_things() {...}тогда, возможно, быстрее, чтобы впасть в грохотl = list_of_things(); if l != null {...}
Брайан Оукли
5
@Bryan: есть большая разница между пустым списком значений и пустой строкой. Строка редко представляет собой список символов.
Кевин Клайн
3
@ Кевин Клайн: конечно. Но в случае строки вы можете захотеть, чтобы эта строка появлялась в журнале, независимо от того, является ли она пустой или нет. Необходимость проверить, является ли оно пустым, чтобы вы могли напечатать пустую строку, скрывает истинное намерение. Или, может быть, это что-то вроде поля базы данных, которое содержит пользовательский контент, который вы хотите добавить на веб-страницу. Это легче сделать, emit(user.hometown)чемif user.hometown == null { emit("") else {emit(user.hometown)}
Брайан Окли
1
Это не только дополнительная печать (не имеет большого значения), но и влияет на читабельность. Я лично нахожу код с кучей нулевых проверок, отвлекающих.
ToddR
82

Во всем коде, который я пишу, я избегаю возврата nullиз функции. Я прочитал это в Чистом Коде .

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

В F # вы можете вернуть optionтип, который может быть some(Person)или none, так что для вызывающей стороны очевидно, что они должны проверить.

Аналогичным C # (анти) паттерном является Try...метод:

public bool TryFindPerson(int personId, out Person result);

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

class FindResult<T>
{
   public FindResult(bool found, T result)
   {
       this.Found = found;
       this.Result = result;
   }

   public bool Found { get; private set; }
   // Only valid if Found is true
   public T Result { get; private set;
}

public FindResult<Person> FindPerson(int personId);

... и, честно говоря, вы можете предположить, что каждый программист .NET знает о Try...шаблоне, потому что он используется внутри .NET Framework. Это означает, что им не нужно читать документацию, чтобы понять, что она делает, что для меня важнее, чем придерживаться какого-то пуристского взгляда на функции (понимание, что resultэто outпараметр, а не refпараметр).

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

Если, с другой стороны, нет логической причины, по которой вызывающая сторона когда-либо предоставит personIdнесуществующий объект , я, вероятно, сделал бы это

public Person GetPerson(int personId);

... а потом я бы бросил исключение, если оно было недействительным. Get...Префикс означает , что абонент знает , что это удастся.

Скотт Уитлок
источник
28
+1, я бы ответил на этот вопрос со ссылкой на Чистый код, если вы еще этого не сделали. Мне нравится мантра: «ЕСЛИ ВАША ФУНКЦИЯ НЕ МОЖЕТ ДЕЛАТЬ ТО, ЧТО В ЭТОМ НАЗВАНИИ, ТОГДА БРОСАЛ ИСКЛЮЧЕНИЕ». Намного лучше, чем проверять на ноль каждые дюжины строк или около того ....
Грэм
13
Я отказался от предположения о знаниях людей.
CaffGeek
5
«Проблема с использованием нулевого значения заключается в том, что человек, использующий интерфейс, не знает, является ли нулевой возможный результат, и должны ли они проверять его, потому что нет не нулевого ссылочного типа». Поскольку ссылочные типы могут быть нулевыми, разве вы не можете всегда предполагать, что нулевой возможный результат?
Томми Карли
4
Если функция возвращает указатель (C / C ++) или ссылку на объект (Java), я всегда предполагаю, что она может вернуть ноль.
Джорджио
7
«Проблема с использованием нулевого значения заключается в том, что человек, использующий интерфейс, не знает, является ли нулевой возможный результат, и должны ли они проверять его, [...]» Если метод может вернуть нулевое значение, это должно быть явно упоминается как часть контракта API.
Жолт Тёрёк
28

Вы можете попробовать шаблон Специального случая Мартина Фаулера из Paterns of Enterprise Application Architecture :

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

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

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

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

Томас Оуэнс
источник
Я столкнулся с этим сценарием, но только после того, как программное обеспечение было выпущено. Мои тестовые данные никогда не вызывали его, так что это было немного неожиданно и было сложно отлаживать. Хотя я и не решил эту проблему с помощью шаблона Special Case, полезно знать об этом.
Самис
14

Я бы подумал, ReverseString()что вернул бы обратную строку, и IllegalArgumentExceptionесли бы передал в Null.

Я думаю, что FindPerson()следует следовать шаблону NullObject или выдвигать неконтролируемое исключение, касающееся отсутствия чего-либо, если вы всегда сможете найти что-то.

NullНужно иметь дело с тем , чего следует избегать. Имея Nullв языках был назван миллиард долларов Ошибка по его изобретатель!

Я называю это моей ошибкой в ​​миллиард долларов. Это было изобретение нулевой ссылки в 1965 году. В то время я разрабатывал первую всеобъемлющую систему типов для ссылок на объектно-ориентированном языке (ALGOL W).

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

Это привело к бесчисленным ошибкам, уязвимостям и сбоям системы, которые, вероятно, причинили миллиард долларов боли и ущерба за последние сорок лет.

В последние годы ряд программных анализаторов, таких как PREfix и PREfast в Microsoft, использовались для проверки ссылок и предупреждения, если существует риск, что они могут быть ненулевыми. Более поздние языки программирования, такие как Spec #, ввели объявления для ненулевых ссылок. Это решение, которое я отверг в 1965 году.

Тони Хоар


источник
11

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

hugomg
источник
1
Интересно. Как реализовать опцию в Java? А в С ++?
Джорджио
1
@Giorgio, Для Java библиотеки Guava от Google имеют класс Optional .
Отавио Маседо
1
Для C ++ естьboost::optional<T>
MSalters
8

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

Тем не менее, я склонен на сторону сторонников возврата нуля. Я нахожу, что есть важное различие в вызове метода, и он отвечает " У меня нет данных", и он отвечает "У меня есть эта пустая строка" .

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

Теперь рассмотрим альтернативу, где вы возвращаете действительный объект Person ... в котором ничего нет. Вы ставите пустые значения во все его значения (имя, адрес, FavoritesDrink), или вы теперь наполняете их действительными, но пустыми объектами? Как ваш клиент теперь может определить, что фактическое лицо не было найдено? Нужно ли им проверять, является ли имя пустой строкой вместо нуля? Разве такого рода вещи не приведут к большому или большему количеству беспорядка в коде и условных операторов, чем если бы мы только что проверили нулевое значение и пошли дальше?

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

Roņu
источник
Разница в том, « возвращает FindPersonили GetPersonвозвращает ноль или выбрасывает исключение, если ключ не существует?» Как пользователь API я просто не знаю, и я должен проверить документацию. С другой стороны, bool TryGetPerson(Guid key, out Person person)не требует, чтобы я проверял документацию, и я знаю, что исключение не выдается в том, что составляет довольно не исключительное обстоятельство. Это то, что я пытаюсь сделать в своем ответе.
Скотт Уитлок
4
Я думаю, что люди слишком привязаны к исключениям. Исключения являются плохими и ресурсоемкими. Не говоря уже о том, что люди пытаются поймать утверждения, ничего не решая. Исключения являются явным признаком того, что что-то пошло не так. Например, нулевые ссылки выдают исключение, потому что это явно неправильно ссылаться на нулевые объекты. Неправильно использовать его, чтобы проверить, был ли человек найден или нет.
Владимир Кочанчич
1
@VladimirKocjancic: Я полностью согласен: исключения должны использоваться для исключительных ситуаций, таких как ошибки программного обеспечения, сбои оборудования, неправильная конфигурация системы. Если вы вычисляете частичную функцию (например findPerson), абсолютно нормально, чтобы не было никакого результата. Это не должно приводить к исключению.
Джорджио
6

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

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

for thing in get_list_of_things() {
    do_something_clever(thing)
}

Мне не нужно было добавлять особый случай для случая, когда нет вещей .

Брайан Оукли
источник
7
В тех случаях, когда ожидается список или другая группа значений, я всегда решаю вернуть пустой список, именно по этой причине. Действие по умолчанию (итерации по пустому списку) почти всегда верно, и если это не так, вызывающая сторона может явно проверить, является ли список пустым.
TMN
5

Это зависит от семантики метода. Вы можете указать, что ваш метод принимает только «Не ноль». В Java вы можете объявить это, используя некоторые аннотации метаданных:

string ReverseString(@NotNull String stringToReverse)

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

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

Person FindPerson(int personID)

Если вы ищете человека по какому-то угаданному идентификатору (что мне кажется странным), вам лучше объявить этот метод как @Nullable.

Мартин Веймелка
источник
3

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

if (someObject != null && someObject.someMethod () != whateverValue)

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

В тех случаях, когда возврат nullимеет смысл (например, вызывая findPerson ()метод), я бы попытался, по крайней мере, предоставить метод, который возвращает, если объект присутствует ( personExists (int personId)например), другим примером может быть containsKey ()метод Mapв Java. Это делает код вызывающего абонента чище, так как вы можете легко увидеть, что существует вероятность того, что требуемый объект может быть недоступен (человек не существует, ключ отсутствует на карте). Постоянная проверка, не ссылается ли ссылка nullна код, по моему мнению.

Laf
источник
3

Нуль лучше всего вернуть, если и только если применяются следующие условия:

  • нулевой результат ожидается при нормальной работе . Можно ожидать, что вы не сможете найти человека при некоторых разумных обстоятельствах, поэтому метод findPerson (), возвращающий значение null, подойдет. Однако, если это действительно неожиданный сбой (например, в функции с именем saveMyImportantData ()), вам следует выдать исключение. В названии есть подсказка - исключения для исключительных обстоятельств!
  • null используется для обозначения «не найдено / нет значения» . Если вы имеете в виду что-то еще, то верните что-то еще Хорошими примерами могут служить операции с плавающей запятой, возвращающие бесконечность или NaN - это значения с определенным значением, поэтому было бы очень запутанно, если бы вы вернули ноль здесь.
  • Функция предназначена для возврата одного значения , такого как findPerson (). Если он был разработан для возврата коллекции, например findAllOldPeople (), тогда лучше всего использовать пустую коллекцию. Следствием этого является то, что функция, которая возвращает коллекцию, никогда не должна возвращать ноль .

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

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

Наконец, если вы примените эти правила к двум функциям, перечисленным в вопросе:

  • FindPerson - было бы целесообразно, чтобы эта функция возвращала ноль, если человек не был найден
  • ReverseString - кажется, что никогда не удастся найти результат, если передать строку (поскольку все строки могут быть обращены, включая пустую строку). Так что он никогда не должен возвращать ноль. Если что-то идет не так (нехватка памяти?), То должно выдать исключение.
mikera
источник
1

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

Я обычно придерживаюсь следующего подхода. Я рассматриваю вызов функции или метода f (v1, ..., vn) как применение функции

f : S x T1 x ... x Tn -> T

где S это «состояние мира» T1, ..., Tn - типы входных параметров, а T - тип возвращаемого значения.

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

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

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

Например, предположим, что у меня есть класс Customer, и я хочу реализовать метод

Customer findCustomer(String customerCode)

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

  • Вернуть объект класса Customer, если запрос выполнен успешно,
  • Вернуть ноль, если запрос не находит клиента.
  • Бросьте исключение, если невозможно подключиться к базе данных.

Дополнительные проверки для нуля, например

Customer customer = findCustomer("...");
if (customer != null && customer.getOrders() > 0)
{
    ...
}

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

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

Я также хотел бы рассмотреть возможность использования шаблона Null Object (как предложено Laf), пока я могу отличить нулевой объект класса от всех других объектов.

Джорджио
источник
0

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

Фани
источник
0

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

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

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

Лорен Печтель
источник
0

Добавим к тому, что люди уже сказали о Maybeконструкторе типов:

Другим большим преимуществом, кроме того, чтобы не рисковать NPE, является семантический. В функциональном мире, где мы имеем дело с чистыми функциями, нам нравится пытаться создавать функции, которые при применении в точности эквивалентны их возвращаемому значению . Рассмотрим случай String.reverse(): это функция, которая с определенной строкой представляет обратную версию этой строки. Мы знаем, что эта строка существует, потому что каждая строка может быть обращена (строки - это в основном упорядоченные наборы символов).

Теперь о чем findCustomer(int id)? Эта функция представляет клиента с указанным идентификатором. Это то, что может или не может существовать. Но помните, функции имеют одно возвращаемое значение, поэтому вы не можете сказать «эта функция возвращает клиента с заданным идентификатором ИЛИ возвращает null.

Это моя главная проблема как с возвратом, так nullи с возвратом нулевого объекта. Они вводят в заблуждение. nullне является клиентом, и на самом деле это не "отсутствие клиента". Это отсутствие НИЧЕГО. Это просто указатель на НИЧЕГО. Очень низкоуровневый, очень уродливый и очень подверженный ошибкам. Я думаю, что нулевой объект также вводит в заблуждение. Нулевой клиент - это клиент. Это не отсутствие, это не клиент с запрашиваемым идентификатором, поэтому возвращать его просто НЕПРАВИЛЬНО. Это НЕ тот клиент, о котором я просил, но вы утверждаете, что вернули клиента. У него неправильный идентификатор, очевидно, это ошибка. Это нарушает договор, предложенный именем метода и подписью. Требуется, чтобы клиентский код предполагал что-то о вашем дизайне или читал документацию.

Обе эти проблемы решаются с помощью Maybe Customer. Неожиданно мы не говорим «эта функция представляет клиента с заданным идентификатором». Мы говорим: «Эта функция представляет клиента с заданным идентификатором, если он существует . Теперь он очень четко и ясно рассказывает о том, что он делает. Если вы попросите клиента с несуществующим идентификатором, вы получите Nothing. Как это лучше? чем null? Не только для риска NPE. Но также и потому, что тип Nothingне просто Maybe. Это Maybe Customer. Он имеет семантическое значение. Он, в частности, означает «отсутствие клиента», указывая на то, что такого клиента не существует.

Другая проблема с нулем, конечно, в том, что он неоднозначен. Это вы не нашли клиента или произошла ошибка соединения с БД, или мне просто не разрешили увидеть этого клиента?

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

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

Сара
источник
0

1) Если семантика функции заключается в том, что она ничего не может вернуть, вызывающая программа ДОЛЖНА проверить это, в противном случае он будет, например. возьми свои деньги и никому их не отдай.

2) Хорошо делать функции, которые семантически всегда что-то возвращают (или бросают).

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

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

user470365
источник
-1
  • NULL должен быть возвращен, если приложение ожидает, что данные будут доступны, но данные недоступны. Например, сервис, который возвращает CITY на основе почтового индекса, должен возвращать ноль, если город не найден. Затем вызывающий абонент может решить обработать нулевое значение или взорвать.

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

java_mouse
источник
-2

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

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

Проверьте это сообщение в блоге для подробного объяснения: http://www.yegor256.com/2014/05/13/why-null-is-bad.html

yegor256
источник