У мене є метод, який повинен повернути об'єкт, якщо він знайдений.
Якщо його не знайти, чи слід:
- повернути null
- кинути виняток
- інший
У мене є метод, який повинен повернути об'єкт, якщо він знайдений.
Якщо його не знайти, чи слід:
Відповіді:
Якщо ви завжди розраховуєте знайти значення, тоді киньте виняток, якщо воно відсутнє. Виняток означав би, що виникла проблема.
Якщо значення може бути відсутнім або присутнім, і обидва є дійсними для логіки програми, тоді поверніть нуль.
Більш важливо: що ви робите в інших місцях у коді? Важлива послідовність.
GetPersonById(25)
кине, якщо цю особу буде видалено, але GetPeopleByHairColor("red")
поверне порожній результат. Отже, я думаю, що параметри щось говорять про очікування.
Виключення викидайте лише в тому випадку, якщо це справді помилка. Якщо очікується, що поведінка об'єкта не існує, поверніть нуль.
Інакше це питання переваги.
Як правило, якщо метод завжди повинен повертати об'єкт, тоді переходьте за винятком. Якщо ви передбачите випадковий нуль і хочете певним чином його обробити, перейдіть до нуля.
Що б ви не робили, я настійно раджу проти третього варіанту: повернення рядка з написом "WTF".
Якщо null ніколи не вказує на помилку, просто поверніть null.
Якщо null - це завжди помилка, киньте виняток.
Якщо null іноді є винятком, тоді кодуйте дві підпрограми. Один звичайний викидає виняток, а інший - булева перевірка, яка повертає об'єкт у вихідний параметр, а підпрограма повертає помилку, якщо об'єкт не був знайдений.
Важко неправильно використати спробу рутини. Справді просто забути перевірити наявність нуля.
Отже, коли null - це помилка, ви просто пишете
object o = FindObject();
Коли null не є помилкою, ви можете кодувати щось на кшталт
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
find
і findOrFail
від Laravel Eloquent
TryFindObject
методу? Кортежі здаються більшою мірою ледачою парадигмою для програмістів, які не хочуть витрачати час на визначення об'єкта, який інкапсулює декілька значень. Це по суті всі кортежі в будь-якому разі в основі.
Я просто хотів переказати варіанти, згадані раніше, кидаючи нові:
Або ви можете комбінувати ці варіанти:
Надайте декілька перевантажених версій вашого геттера, щоб абонент міг вирішити, яким шляхом піти. У більшості випадків лише перший має реалізацію алгоритму пошуку, а інші просто обертаються навколо першого:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Навіть якщо ви вирішите надати лише одну реалізацію, ви можете скористатись такою конвенцією про іменування для уточнення свого контракту, і це допоможе вам, якщо ви коли-небудь вирішите додати і інші реалізації.
Ви не повинні зловживати цим, але це може бути корисним, особливо при написанні допоміжного класу, який ви будете використовувати в сотнях різних додатків з багатьма різними умовами обробки помилок.
Expected<T> findObject(String)
де Expected<T>
є функції orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. Це
Використовуйте нульовий шаблон об'єкта або киньте виняток.
Person somePerson = personRepository.find("does-not-exist");
припустимо, що цей метод повертає нульовий об'єкт для ID does-not-exist
. Для чого тоді правильна поведінка somePerson.getAge()
? Наразі я ще не впевнений, що нульовий шаблон об'єкта є правильним рішенням для пошуку сутностей.
Переваги кидання винятку:
Детальніше з прикладами див. На веб-сторінці : http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
це залежить, якщо ваша мова та код рекламують: LBYL (подивіться, перш ніж стрибати) або EAFP (простіше просити пробачення, ніж дозволу)
LBYL каже, що ви повинні перевірити значення (тому поверніть нуль).
EAFP каже просто спробувати операцію і побачити, чи не вдалося вона (киньте виняток)
хоча я згоден з вище. Винятки повинні використовуватися для виключних умов / помилок, а повернення нуля найкраще використовувати під час перевірки.
EAFP vs. LBYL на Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html
( веб-архів )
Просто запитайте себе: "чи є винятковим випадком, що об'єкт не знайдений"? Якщо, як очікується, це відбудеться у звичайному процесі вашої програми, ви, ймовірно, не повинні створювати виняток (оскільки це не виняткова поведінка).
Коротка версія: використовуйте винятки для обробки виняткової поведінки, а не для управління нормальним потоком управління у вашій програмі.
-Алан.
Винятки пов'язані з дизайном за контрактом.
Інтерфейс об'єктів - це фактично договір між двома об'єктами, абонент повинен відповідати договору, інакше одержувач може просто вийти з винятку. Можливі два контракти
1) весь метод методу є дійсним, і тоді ви повинні повернути нуль, коли об'єкт не знайдений.
2) справедливий лише деякий вхід, тобто той, що призводить до знайденого об'єкта. У такому випадку ви ОБОВ'ЯЗКИ запропонувати другий метод, який дозволяє абоненту визначити, чи буде його введення правильним. Наприклад
is_present(key)
find(key) throws Exception
ЯКЩО і ТОЛЬКО, якщо ви надаєте обидва способи 2-го контракту, ви можете кинути виняток, нічого не знайдено!
Залежить від того, що означає, що об’єкт не знайдено.
Якщо це нормальний стан справ, то поверніть нуль. Це просто щось, що може траплятися раз у раз, і абоненти повинні перевірити це.
Якщо це помилка, тоді киньте виняток, абоненти повинні вирішити, що робити зі станом помилки відсутнього об'єкта.
Зрештою, і це спрацювало б, хоча більшість людей взагалі вважають за добру практику використовувати Винятки лише тоді, коли щось, ну, Винятковий.
Ось ще пара пропозицій.
Якщо ви повертаєте колекцію, уникайте повернення нуля, поверніть порожню колекцію, що полегшує облік з попереднім перевіркою без нульової перевірки.
Декілька .NET API використовують шаблон параметру castOnError, який надає абоненту можливість вибору, чи справді це виняткова ситуація чи ні, якщо об'єкт не знайдений. Type.GetType - приклад цього. Ще одна поширена модель з BCL - це модель TryGet, де повертається булева інформація і передається значення через вихідний параметр.
Ви також можете розглянути шаблон нульового об’єкта за деяких обставин, які можуть бути або за замовчуванням, або версіями без поведінки. Ключ - уникнути нульових перевірок у всій базі коду. Дивіться тут для отримання додаткової інформації http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
Поверніть нуль замість викидання виключення та чітко задокументуйте можливість повернення нульового значення в документації API. Якщо викликовий код не вшановує API і перевіряє нульовий випадок, то, швидше за все, це все одно призведе до якогось "виключення з нульовим покажчиком" :)
У C ++ я можу придумати 3 різні смаки налаштування методу, який знаходить об’єкт.
Варіант А
Object *findObject(Key &key);
Повернути нуль, коли об’єкт неможливо знайти. Приємно і просто. Я б пішов з цим. Альтернативні підходи, наведені нижче, призначені для людей, які не ненавидять зловживань.
Варіант В
void findObject(Key &key, Object &found);
Передайте посилання на змінну, яка буде отримувати об'єкт. Метод викинув виняток, коли об’єкт неможливо знайти. Ця умова, ймовірно, більше підходить, якщо насправді не очікується, що об’єкт не буде знайдений - значить, ви кидаєте виняток, щоб означати, що це несподіваний випадок.
Варіант С
bool findObject(Key &key, Object &found);
Метод повертає значення false, коли об'єкт не може бути знайдений. Перевага цього варіанту перед тим, що ви можете перевірити випадок помилки одним чітким кроком:
if (!findObject(myKey, myObj)) { ...
маючи на увазі лише той випадок, коли null не вважається винятковою поведінкою, я, безумовно, є методом спробу, зрозуміло, що не потрібно "читати книгу" чи "дивитися, перш ніж стрибати", як тут було сказано
так в основному:
bool TryFindObject(RequestParam request, out ResponseParam response)
а це означає, що код користувача також буде зрозумілим
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
Як правило, він повинен повернутись до нуля. Код, що викликає метод, повинен вирішити, кинути виняток чи спробувати щось інше.
Або повернути Варіант
Опція - це клас контейнерів, який змушує клієнта обробляти шафи. У Scala є ця концепція, знайдіть API.
Тоді у вас є такі методи, як T getOrElse (T valueIfNull) на цьому об'єкті, або повернення знайденого об'єкта, або інтернативне, яке вказує клієнт.
На жаль, JDK суперечить, якщо ви намагаєтеся отримати доступ до неіснуючого ключа в пакеті ресурсів, ви не знайдете винятку, і коли ви вимагаєте значення з карти, ви отримуєте нульове значення, якщо воно не існує. Тож я змінив би відповідь переможця на наступне, якщо знайдене значення може бути нульовим, тоді піднімемо виняток, коли воно не знайдено, інакше повернути нуль. Тож дотримуйтесь правила за одним винятком, якщо вам потрібно знати, чому значення не знайдено, то завжди піднімайте виняток, або ..
Поки він повинен повернути посилання на об'єкт, повернення NULL повинно бути хорошим.
Однак якщо вона повертає всю криваву річ (як, наприклад, у C ++, якщо ви робите: 'return blah;', а не 'return & blah;' (або 'blah' - вказівник), ви не можете повернути NULL, тому що це не типу "об'єкт". У такому випадку я б підійшов до проблеми, якщо викинути виняток або повернути порожній об'єкт, на якому не встановлено прапор успіху.
Не думайте, що хтось згадав про накладні витрати на обробку винятків - потребує додаткових ресурсів для завантаження та обробки винятку, якщо тільки справжня подія вбивства або зупинки процесу (подальший вперед не спричинить більше шкоди, ніж користі), я б вирішив повернути назад значення середовища, що викликає, може інтерпретувати так, як вважає за потрібне.
Я погоджуюся з тим, що тут здається консенсусом (повернути нуль, якщо "не знайдено" - це нормально можливий результат, або викинути виняток, якщо семантика ситуації вимагає, щоб об'єкт завжди знаходився).
Однак існує третя можливість, яка може мати сенс залежно від вашої конкретної ситуації. Ваш метод може повернути об'єкт за замовчуванням якогось типу в умові "не знайдено", що дозволяє виклику коду бути впевненим, що він завжди отримає дійсний об'єкт без необхідності перевірки нуля або вилучення виключень.
Винятки повинні бути винятковими . Повернути null, якщо він дійсний для повернення нуля .
Якщо метод повертає колекцію, повертайте порожню колекцію (як сказано вище). Але, будь ласка, не Collections.EMPTY_LIST чи подібні! (у випадку з Java)
Якщо метод отримує один об'єкт, у вас є деякі варіанти.
Будьте уважні, якщо вирішите повернути нуль. Якщо ви не єдиний програміст у проекті, ви отримаєте NullPointerExceptions (на Java або що-небудь в інших мовах) під час виконання! Тому не повертайте нулі, які не перевіряються під час компіляції.
null
. Докладнішу інформацію див. У відповіді.
Якщо ви використовуєте бібліотеку чи інший клас, який видає виняток, вам слід повторно скинути її. Ось приклад. 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.