Очікувана поведінка, коли запит на колекцію матиме нульові елементи


13

Скажімо, вам дано наступне ...

List<Thing> theThings = fubar.Things.All();

Якби нічого не повернути, чого б ти очікував, що повернеться фубар.

Редагувати: Дякую за думки. Я трохи зачекаю і прийму запис із більшою кількістю вікон.

Я погоджуюся з відповідями на даний момент, особливо тими, що пропонують порожню колекцію. Постачальник надав API з кількома дзвінками, подібними до наведеного вище. Продавець, який минулого року отримав 4,6 млн. Доларів доходу через свої API (API), BTW. Вони роблять те, з чим я принципово не згоден - вони викидають виняток.


Здається, це досить твердий консенсус [тут] [1]: Порожня колекція. Завжди. [1]: stackoverflow.com/questions/1969993/…
Джессі К. Слікер

Для чого тип даних Things? Якщо має сенс Thingsповернути поле null, то для вас є сенс отримати виняток, оскільки ви не перевіряли на null перед вашим дзвінком All(). Однак я згоден з людьми, які думають, що fubar.Thingsповинні повернути порожню колекцію замість нульової.
Колін Д

Я бачу, до чого ти добираєшся, Колін. У цьому випадку ви можете припустити, що Речі існують, і All () є статичним. Виняток стосується того, що колекція порожня, а не якась інша причина.
abscode

OMG вони кидають виняток ...! o_O
Стюарт Марк

Тепер цікавішим питанням буде те, яка причина на землі може когось кинути в такій загальній справі, або що робить справу такою особливою, щоб вимагати кидання ??!
Мартін Ба

Відповіді:


29

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

List<Thing> theThings = fubar.Things.All();
if (theThings != null) {
    for (Thing t : theThings) {
        t.doSomething();
    }
}

вони зможуть написати це:

List<Thing> theThings = fubar.Things.All();
for (Thing t : theThings) {
    t.doSomething();
}

Цей другий фрагмент коду коротший і легший для читання, оскільки рівень гніздування нижчий на одиницю.


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

@ X-Zero Але якщо ви голі на голову, "володіння в рюкзаку" можуть повернути нульовий набір, оскільки у вас навіть рюкзак у вас немає. Це може бути BackpackNotFoundException, але тільки якщо це справді несподівано. Це повинно бути нормальним станом у, скажімо, грі на виживання на острові.
Ізката

Додаткова нульова перевірка - це те, що допомагає мені спати вночі.
Джоель Б

6

Я б очікував порожнього списку. theThingsбуде по- , як і раніше бути об'єктом, але theThings.Countі theThings.size()повернеться 0.


5

Такі проблеми дизайну вирішуються за допомогою моделі Null Object

... Замість використання нульової посилання, щоб передати відсутність об'єкта (наприклад, неіснуючого клієнта), використовується об’єкт, який реалізує очікуваний інтерфейс, але тіло методу якого порожнє. Перевага такого підходу перед робочою реалізацією за замовчуванням полягає в тому, що Null Object дуже передбачуваний і не має побічних ефектів: він нічого не робить.

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

Пропозиція, особливо застосовна у вашому випадку (повернення, Listколи немає Thing), є:

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


3

Вам слід, IMHO, повернути значення EMPTY. Я не знаю про C #, але в Java у нас є це:

  List list = Collections.EMPTY_LIST;
  Set set = Collections.EMPTY_SET;
  Map map = Collections.EMPTY_MAP;

  // For the type-safe 
  List<String> s = Collections.emptyList();
  Set<Long> l = Collections.emptySet();
  Map<Date> d = Collections.emptyMap();

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html


1
Еквівалент C # є Enumerable.Empty<T>(), який повертає порожнє IEnumerable<T>(див. Msdn.microsoft.com/en-us/library/bb341042.aspx )
Авнер Шахар-Каштан

1
Поточні документи тут: docs.oracle.com/javase/7/docs/api/java/util/Collections.html - 1.4.2 документа тепер близько десяти років.
Стюарт відзначає

2

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


2

Два рішення вони означають різні речі.

Якщо річ, яку ви повертаєте, є лише нулем, ВИНАГО повертаєте порожню колекцію! Візьміть справу зі списком каталогів. Якщо в каталозі немає файлів, ви повернете порожню колекцію файлів.

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


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