Чи краще повернути 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 Object ( ), абонент повинен буде перевірити, чи є об'єкт Person NULL чи порожнім, перш ніж робити щось з ним (наприклад, дзвінок UpdateName()). То чому б просто не повернути NULL сюди, а потім абоненту потрібно лише перевірити NULL.

Хтось ще бореться з цим? Будь-яка допомога чи розуміння цінується.


2
Він буде різним. Ви також можете стверджувати, що метод повинен зупиняти значення, які є невірними наперед, наприклад, ваш параметр stringToReverse передається як порожній або нульовий. Якщо ви виконали цю перевірку (відкинули виняток), вона завжди поверне щось інше, ніж null.
Аарон Маківер

Фаулер POEAA - с. 496 Основні шаблони - Особливий випадок (нульовий об’єкт) Bloch Effective Java, 2-е видання Пункт 43: Повернення порожніх масивів чи колекцій, а не
нульових даних

1
@Boris Я не побачив твій коментар. Я фактично щойно опублікував Особливий випадок як відповідь.
Томас Оуенс

@Thomas я не бачу в цьому жодної проблеми :). Що стосується питання, то все одно це питання здорового глузду.
Борис Треухов

Цікавим коментарем є те, що в базах даних Oracle NULL і порожня рядок однакові
WuHoUnited

Відповіді:


77

StackOverflow має хорошу дискусію про точну темі в цьому Q & A . У найвищому рейтингу кроноз зазначає:

Повернення нуля зазвичай є найкращою ідеєю, якщо ви маєте намір вказати, що немає даних.

Порожній об’єкт означає, що дані повернуті, тоді як повернення нуля чітко вказує на те, що нічого не повернуто.

Крім того, повернення нуля призведе до нульового виключення, якщо ви намагаєтеся отримати доступ до членів об’єкта, що може бути корисно для виділення баггі-коду - спроба отримати доступ до члена нічого не має сенсу. Доступ до членів порожнього об'єкта не пройде, тобто помилки можуть не виявити.

Особисто мені подобається повертати порожні рядки для функцій, які повертають рядки, щоб мінімізувати обробку помилок, яку потрібно встановити. Однак вам потрібно переконатися, що група, з якою працюєте, буде дотримуватися тієї ж конвенції - інакше переваги від цього рішення не будуть досягнуті.

Однак, як зазначалося у афіші відповіді на відповідь, нулі, ймовірно, повинні бути повернені, якщо очікується об'єкт, щоб не виникало сумнівів у поверненні даних.

Зрештою, немає єдиного найкращого способу вчинити справи. Створення консенсусу в команді призведе до кращого досвіду вашої команди.


8
Особисто мені подобається повертати порожні рядки для функцій, які повертають рядки, щоб мінімізувати обробку помилок, яку потрібно встановити. Ніколи не розумів цього аргументу. Нульова перевірка - це що, максимум <10 знаків? Чому ми поводимось так, що це назад вигинання праці?
Аарон Маківер

19
Ніхто не сказав, що це повертає працю. Але це праця. До коду додається особливий випадок, що означає ще одну гілку для тестування. Плюс це порушує потік коду. for x in list_of_things() {...}Це, швидше, швидше, а потімl = list_of_things(); if l != null {...}
Брайан Оуклі

5
@Bryan: велика різниця між порожнім списком значень і порожнім рядком. Рядок рідко представляє список символів.
Кевін клайн

3
@kevin cline: звичайно. Але у випадку з рядком, можливо, ви хочете, щоб ця рядок відображалася в журналі, незалежно від того, чи це недійсна чи ні. Потрібно перевірити, чи недійсне воно, щоб ви могли надрукувати порожній рядок, що придумує реальний намір. Або, можливо, це щось на зразок поля бази даних, яке містить внесений користувачем вміст, який ви хочете додати на веб-сторінку. Це зробити легше, 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 рамкою. Це означає, що їм не потрібно читати документацію, щоб зрозуміти, що вона робить, що для мене важливіше, ніж дотримуватися певного погляду на функції пуриста (розуміння, що resultце outпараметр, а не refпараметр).

Тож я б пішов з TryFindPersonтим, що ти, схоже, вказуєш, що це абсолютно нормально - не в змозі його знайти.

Якщо, з іншого боку, немає жодної логічної причини, щоб абонент коли-небудь надав такий, personIdякий не існував, я, мабуть, зробив би це:

public Person GetPerson(int personId);

... і тоді я б кинув виняток, якщо він недійсний. Get...Префікс означає , що абонент знає , що це вдасться.


28
+1, я відповів би на це запитання з посиланням на Clean Code, якщо ви цього ще не робили. Мені подобається мантра: "ЯКЩО ВАШ ФУНКЦІОННИЙ КАНТ ДІЙСЯ, ЩО ІМЕ ВЗАЄТЬСЯ, ТОГО ПРИКЛЮЧАЙТЕ ВИКОНАННЯ" Muuuch краще, ніж перевіряти на нуль кожні десятки рядків чи так ...
Грем

13
Я відмовився припускати щось про знання людей.
CaffGeek

5
"Проблема з використанням null полягає в тому, що особа, що використовує інтерфейс, не знає, чи є null можливим результатом, і чи повинні вони перевірити це, оскільки немає недійсного посилання типу." Оскільки типи посилань можуть бути нульовими, чи не завжди ви можете припустити, що нуль є можливим результатом?
Томмі Карльєр

4
Якщо функція повертає вказівник (C / C ++) або посилання на об'єкт (Java), я завжди припускаю, що він може повернути нуль.
Джорджіо

7
"Проблема з використанням null полягає в тому, що людина, що використовує інтерфейс, не знає, чи є null можливим результатом, і чи повинні вони перевірити її, [...]" Якщо метод може повернути null, це має бути явно згадується як частина договору API.
Zsolt Török

28

Ви можете спробувати шаблон спеціальної справи Мартіна Фаулера з " Шаблони архітектури корпоративних додатків" :

Нулі - це незручні речі в об'єктно-орієнтованих програмах, оскільки вони перемагають поліморфізм. Зазвичай ви можете вільно запускати foo на змінну посилання даного типу, не турбуючись про те, чи є елемент точного типу або підклас. За допомогою сильно набраної мови ви навіть можете змусити компілятор перевірити правильність виклику. Однак, оскільки змінна може містити null, ви можете зіткнутися з помилкою виконання, викликаючи повідомлення на null, що отримає вам приємний дружній слід стека.

Якщо змінна може бути нульовою, ви повинні пам'ятати, щоб оточити її нульовим тестовим кодом, щоб ви зробили правильно, якщо нуль присутній. Часто правильна річ у багатьох контекстах однакова, тому ви нарешті пишете подібний код у багатьох місцях - вчиняючи гріх дублювання коду.

Нули є поширеним прикладом подібних проблем, і інші з'являються регулярно. У системах числення вам доводиться мати справу з нескінченністю, яка має спеціальні правила для таких речей, як складання, які порушують звичайні інваріанти реальних чисел. Один з моїх найдавніших досвіду роботи з програмним забезпеченням для бізнесу був із клієнтом комунальних послуг, який не був повністю відомий, іменувався "пасажиром". Усе це передбачає зміну звичної поведінки типу.

Замість того, щоб повернути нулеве або якесь непарне значення, поверніть спеціальний кейс, який має той самий інтерфейс, що і очікуючий абонент.


Я зіткнувся з цим сценарієм, але лише після виходу програмного забезпечення. Дані моїх тестів ніколи не викликали цього, тому це було трохи не в силі і біль налагодити. Хоча я не вирішив це за допомогою шаблону особливих випадків, добре це знати.
Саміс

14

Я б подумав, ReverseString()що поверне зворотний рядок, і він би кинув, IllegalArgumentExceptionякщо він переданий у Null.

Думаю, FindPerson()слід слідувати шаблону NullObject або створити неперевірений виняток про те, що не знайти щось, якщо ти завжди маєш можливість щось знайти.

Мати справу Null- це те, чого слід уникати. Маючи Nullв мовах був названий мільярд доларів Помилка по його винахідник!

Я називаю це моєю помилкою в мільярд доларів. Це був винахід нульової посилання в 1965 році. Тоді я розробляв першу комплексну систему для посилань на об'єктно-орієнтованій мові (ALGOL W).

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

Це призвело до незліченних помилок, уразливості та збоїв у системі, які, ймовірно, спричинили біль і шкоду в мільярд доларів за останні сорок років.

Останніми роками ряд програмних аналізаторів, таких як PREfix та PREfast в Microsoft, використовувались для перевірки посилань та попередження, якщо існує ризик, що вони можуть бути недійсними. Більш недавні мови програмування, як Spec #, ввели декларації для ненульових посилань. Це рішення, яке я відкинув у 1965 році.

Тоні Хоаре


11

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


1
Цікаво. Як реалізувати опцію в Java? А в С ++?
Джорджіо

1
@Giorgio, Для Java бібліотеки Guava від Google мають клас, який називається Необов’язковий .
Отавіо Македо

1
Для C ++ єboost::optional<T>
MSalters

8

Я бачу обидві сторони цього аргументу, і я усвідомлюю, що деякі досить впливові голоси (наприклад, Фоулер) виступають за те, щоб не повертати нулі, щоб зберегти чистий код, уникати зайвих блоків обробки помилок тощо.

Однак я схильний до сторони прихильників повернення нуля. Я вважаю, що існує важлива відмінність у виклику методу, і він відповідає, у мене немає даних, і це відповідає у мене ця порожня рядок .

Оскільки я бачив деякі дискусії, що стосуються класу Person, розгляньте сценарій, коли ви намагаєтеся шукати екземпляр класу. Якщо ви введете якийсь атрибут Finder (наприклад, ідентифікатор), клієнт може негайно перевірити наявність нуля, щоб перевірити, чи не було знайдено значення. Це не обов'язково є винятковим (отже, не потребує винятків), але це також має бути чітко зафіксовано. Так, це вимагає певної суворості з боку клієнта, і ні, я не думаю, що це зовсім погано.

Тепер розглянемо альтернативу, коли ви повернете дійсний об'єкт Person ..., який не має нічого в ньому. Чи вводите нулі у всі його значення (ім'я, адреса, favoriteDrink), чи тепер ви заповнюєте ті з дійсними, але порожніми об’єктами? Як ваш клієнт зараз визначить, що фактичної особи не знайдено? Чи потрібно їм перевіряти, чи ім'я є порожнім рядком замість null? Невже подібні речі насправді не призведуть до стільки чи більше безладу коду та умовних висловлювань, ніж якби ми просто перевірили наявність нуля та продовжили роботу?

Знову ж таки, є питання з обох сторін цього аргументу, з яким я міг би погодитися, але я вважаю, що це має найбільш сенс для більшості людей (що робить код більш ретельним).


Різниця полягає в тому, " FindPersonчи GetPersonповертає нуль або викидає виняток, якщо ключ не існує?" Як користувач API я просто не знаю і мені потрібно перевірити документацію. З іншого боку, bool TryGetPerson(Guid key, out Person person)від мене не потрібно перевіряти документацію, і я знаю, що виняток не припускається, що є досить невиключною обставиною. Це те, що я намагаюся зробити у своїй відповіді.
Скотт Вітлок,

4
Я думаю, що люди занадто прив’язалися до винятків. Винятки є поганими та витрачають ресурси. Не кажучи вже про те, що люди намагаються вловлювати заяви, не вирішуючи нічого. Винятки - це чітка ознака того, що щось пішло принципово не так. Наприклад, нульові посилання викидають виняток, оскільки явно неправильно посилатися на нульові об'єкти. Неправильно використовувати його, щоб перевірити, знайдена людина чи ні.
Володимир Кочанчич

1
@VladimirKocjancic: Я повністю згоден: винятки слід використовувати для виняткових ситуацій, як помилки програмного забезпечення, збої в апаратному забезпеченні, неправильні налаштування системи. Якщо ви обчислюєте часткову функцію (на зразок findPerson), то повернення результатів абсолютно нормально. Це не повинно призводити до виключення.
Джорджо

6

Поверніть нульове значення, якщо вам потрібно знати, чи існує елемент чи ні. В іншому випадку поверніть очікуваний тип даних. Це особливо актуально, якщо ви повертаєте список елементів. Зазвичай можна з упевненістю припустити, що абонент хоче списку, він хоче повторити його. Багато мов (більшість? Всіх?) Не спрацьовують, якщо ви намагаєтесь повторити значення null, але не тоді, коли ви повторюєте порожній список.

Мені неприємно намагатися використовувати такий код, як тільки це не вдалося:

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

Мені не слід було б додавати окремий випадок для справи, коли немає речей .


7
У випадках, коли очікується список чи інша група значень, я завжди обираю повернути порожній список саме з цієї причини. Дія за замовчуванням (повторення в порожньому списку) майже завжди правильне, і якщо це не так, то абонент може явно перевірити, чи список є порожнім.
TMN

5

Це залежить від семантики методу. Можливо, ви можете вказати, що ваш метод приймає лише "Not null". У 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 ()метод на MapJava). Це робить код абонентів чистішим, оскільки ви можете легко побачити, що існує можливість, що потрібний об’єкт може бути недоступним (людина не існує, ключ не присутній на карті). Постійно перевіряючи, чи є посилання nullзадумливим кодом, на мою думку.


3

null - найкраще повернути лише тоді, якщо застосовуються наступні умови:

  • нульовий результат очікується при нормальній роботі . Можна очікувати, що вам не вдасться знайти людину за якихось розумних обставин, тому знайдітьПерсон (), що повертає нуль, добре. Однак якщо це справді несподіваний збій (наприклад, у функції під назвою saveMyImportantData ()), то вам слід кидати виняток. У назві є підказка - винятки є для виняткових обставин!
  • null використовується для позначення "не знайдено / немає значення" . Якщо ви маєте на увазі щось інше, то поверніть щось інше! Хорошими прикладами можуть бути операції з плаваючою комою, що повертають нескінченність або NaN - це значення із специфічними значеннями, тому це стало б дуже заплутаним, якби ви повернули тут нуль.
  • Функція призначена для повернення єдиного значення , такого як findPerson (). Якщо вона була створена для повернення колекції, наприклад, findAllOldPeople (), тоді найкраща порожня колекція. Наслідком цього є те, що функція, яка повертає колекцію, ніколи не повинна повертати нуль .

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

Якщо дотримуватися цих правил, нулі здебільшого нешкідливі. Зауважте, що якщо ви забудете перевірити наявність null, ви, як правило, отримаєте NullPointerException одразу після цього, що, як правило, досить легко виправити помилку. Цей невдалий підхід набагато кращий, ніж мати підроблене значення повернення (наприклад, порожня рядок), яке спокійно поширюється навколо вашої системи, можливо, пошкоджуючи дані, не кидаючи виняток.

Нарешті, якщо ви застосуєте ці правила до двох функцій, перелічених у питанні:

  • FindPerson - для цієї функції було б доречно повернути нуль, якщо особа не була знайдена
  • ReverseString - здається, ніколи не вдасться знайти результат, якби пройшов рядок (оскільки всі рядки можуть бути зворотні, включаючи порожню рядок). Тому він ніколи не повинен повертати нуль. Якщо щось піде не так (з пам'яті?), То це повинно викинути виняток.

1

На мій погляд, є різниця між поверненням NULL, поверненням порожнього результату (наприклад, порожній рядок або порожній список) і киданням винятку.

Я зазвичай дотримуюся наступного підходу. Я розглядаю виклик функції або методу f (v1, ..., vn) як додаток функції

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

де S it - "стан світу" T1, ..., Tn - типи вхідних параметрів, а T - тип повернення.

Я спершу спробую визначити цю функцію. Якщо функція є частковою (тобто є деякі вхідні значення, для яких вона не визначена), я повертаю NULL, щоб сигналізувати про це. Це тому, що я хочу, щоб обчислення нормально закінчувалося, і сказати мені, що запитувана мною функція не визначена на заданих входах. Використання, наприклад, порожнього рядка як зворотного значення неоднозначне, оскільки може бути, що функція визначена на входах, а порожня рядок - правильний результат.

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

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

Наприклад, припустимо, що у мене є клієнт класу, і я хочу реалізувати метод

Customer findCustomer(String customerCode)

шукати клієнта в базі даних програми за його кодом. У цьому методі я б

  • Поверніть об’єкт класу Клієнт, якщо запит успішний,
  • Поверніть нуль, якщо запит не знайде клієнта.
  • Накиньте виняток, якщо неможливо підключитися до бази даних.

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

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

є частиною семантики того, що я роблю, і я б не просто "пропустив їх" для того, щоб зробити читання коду краще. Я не думаю, що це спрощена практика спростити семантику розглянутої проблеми просто для спрощення коду.

Звичайно, оскільки перевірка на null відбувається дуже часто, чи добре, якщо мова підтримує для неї якийсь спеціальний синтаксис.

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


0

Методи, що повертають колекції, повинні повертатися порожніми, але інші можуть повернути нуль, тому що для колекцій може статися так, що у вас з'явиться об'єкт, але в ньому немає елементів, тож абонент повинен перевірити розмір просто для обох.


0

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

Єдиний випадок, коли я бачу будь-які дебати, - це коли ви повертаєтеся до одного пункту. Мені здається, що я вважаю за краще повернути нуль у разі невдачі в такій ситуації на основі того, що речі швидко виходять з ладу.

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


0

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

Ще один великий приріст, крім того, що не ризикують NPE, - це семантичний. У функціональному світі, де ми маємо справу з чистими функціями, ми любимо намагатися робити функції, які при застосуванні точно еквівалентні їхньому поверненому значенню . Розглянемо випадок String.reverse(): Це функція, яка надає певний рядок, являє собою зворотну версію цього рядка. Ми знаємо, що цей рядок існує, тому що кожен рядок може бути перетворений (рядки - це в основному впорядковані набори символів).

А тепер що findCustomer(int id)? Ця функція представляє клієнта, який має даний ідентифікатор. Це те, що може бути, а може і не існувати. Але пам’ятайте, що функції мають одне повернене значення, тому ви не можете реально сказати, що "ця функція повертає клієнта із заданим ідентифікатором АБО він повертається null.

Це моя головна проблема як з поверненням, так nullі з поверненням нульового об’єкта. Вони вводять в оману. nullне є замовником, і насправді це теж "відсутність замовника". Це відсутність нічого. Це просто безтиповий вказівник на НІЧОГО. Дуже низький і дуже потворний і дуже схильний до помилок. Нульовий об’єкт тут також досить вводить в оману. Нульовий клієнт - це замовник. Це не відсутність одного, це не клієнт із запитуваним ідентифікатором, тому повернення його просто НЕПРАВИЛЬНО. Це НЕ той клієнт, якого я просив, але ви все ще стверджуєте, що повернули клієнта. У нього неправильний ідентифікатор, явно це помилка. Він розриває контракт, запропонований назвою методу та підписом. Він вимагає від клієнтського коду, щоб припускати речі щодо вашого дизайну або читати документацію.

Обидва ці питання вирішуються а Maybe Customer. Раптом ми не кажемо, що "ця функція представляє клієнта з даним ідентифікатором". Ми говоримо, що "ця функція представляє клієнта з даним ідентифікатором, якщо він існує . Тепер він дуже чітко і зрозуміло про те, що він робить. Якщо ви попросите клієнта з неіснуючим ідентифікатором, ви отримаєте Nothing. Як це краще ніж null? Не тільки для ризику NPE. Але також тому, що тип Nothingне просто Maybe. Це Maybe Customer. Він має смислове значення. Це конкретно означає "відсутність замовника", що вказує на відсутність такого замовника.

Ще одна проблема з null - це, звичайно, неоднозначність. Це ви не знайшли клієнта, або сталася помилка підключення db або мені просто не дозволено бачити цього клієнта?

Якщо у вас є кілька випадків помилок, подібних до цієї, ви можете викинути винятки для цих версій, або (і я вважаю за краще цей спосіб) ви можете повернути Either CustomerLoadError Customer, що представляє або щось, що пішло не так, або повернутого клієнта. Він має всі переваги, Maybe Customerа також дозволяє вказати, що може піти не так.

Головне, за чим я хотів, - це захопити договір функції у своєму підписі. Не сприймайте речі, не покладайтеся на швидкоплинні угоди, будьте явні.


0

1) Якщо семантична функція полягає в тому, що вона нічого не може повернути, абонент ПОВИНЕН перевірити її, інакше він зробить, наприклад. візьміть свої гроші і не віддайте їх нікому.

2) Добре робити функції, які семантично завжди щось повертають (або кидають).

За допомогою реєстратора має сенс повернути реєстратор, який не реєструється, якщо не був визначений реєстратор. Повертаючи колекцію, майже ніколи не має сенсу (за винятком "достатньо низького рівня", де сама колекція є даними, а не тим, що вона містить) нічого не повертати, тому що порожній набір - це набір, а не нічого.

На прикладі людини я б пішов «в сплячий» шлях (get vs load, IIRC, але там це ускладнено проксі-об'єктами для ледачого завантаження) з двома функціями: одна, яка повертає нуль, а друга, що кидає.


-1
  • NULL слід повернути, якщо програма очікує, що дані будуть доступні, але дані недоступні. Наприклад, сервіс, який повертає CITY на основі zipcode, повинен повернути нуль, якщо місто не знайдено. Потім абонент може вирішити обробити нуль або підірвати.

  • Порожній список повинен бути повернутий, якщо є дві можливості. Немає даних або немає даних. Наприклад, послуга, яка повертає МІСТ (и), якщо кількість населення перевищує певну кількість. Він може повернути порожній список, якщо немає даних, що відповідають заданим критеріям.


-2

Повернення NULL - це жахливий дизайн в об'єктно-орієнтованому світі. Коротше кажучи, використання NULL призводить до:

  • спеціальна обробка помилок (замість винятків)
  • неоднозначне смислове
  • повільний, а не швидкий збій
  • комп'ютерне мислення проти об’єктного мислення
  • змінні та неповні предмети

Перегляньте цю публікацію в блозі для детального пояснення: http://www.yegor256.com/2014/05/13/why-null-is-bad.html

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.