IllegalArgumentException або NullPointerException для нульового параметра? [зачинено]


547

У мене є простий метод встановлення для властивості і nullне підходить для даної властивості. Мене завжди розривали в цій ситуації: чи варто кидати IllegalArgumentException, чи то NullPointerException? З боку javadocs, обидва здаються доречними. Чи є якийсь зрозумілий стандарт? Або це лише одна з тих речей, якими ви повинні робити все, що завгодно, і обидва справді правильні?

Відповіді:


299

Здається, що IllegalArgumentExceptionзакликається, якщо ви не хочете nullбути дозволеним значенням, і NullPointerExceptionбуло б кинуто, якби ви намагалися використовувати змінну, яка виявляється такою null.


33
Наступні відповіді на це запитання дають переконливі аргументи, що NullPointerException є правильним винятком: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; та stackoverflow.com/a/6358/372926 .
SamStephens

2
IllegalArgumentExceptionсуперечить об'єктам Java: Object.requireNonNull (T) та Guava's Preconditions.checkNotNull (T), який закидає a NullPointerException. Однак правильна відповідь, безумовно IllegalArgumentException , пояснюється у відмінній відповіді Джейсона Коена, і це розділ коментарів .
матоні

417

Ви повинні використовувати IllegalArgumentException(IAE), а не NullPointerException(NPE) з наступних причин:

По-перше, NPE JavaDoc чітко перераховує випадки, коли NPE підходить. Зауважте, що всі вони кидаються під час виконання при nullнеправильному використанні. На відміну від цього, IAE JavaDoc не міг бути більш зрозумілим: "Кинуто для вказівки на те, що метод був переданий незаконним або невідповідним аргументом". Так, це ти!

По-друге, коли ви бачите NPE у сліді стека, що ви припускаєте? Ймовірно, що хтось зневірив a null. Коли ви бачите IAE, ви припускаєте, що виклик методу у верхній частині стека передав незаконне значення. Знову ж таки, останнє припущення вірно, перше вводить в оману.

По-третє, оскільки IAE чітко розроблений для перевірки параметрів, ви повинні вважати це винятком вибору за замовчуванням, то чому б ви вибрали NPE? Звичайно, не для різної поведінки - чи дійсно ви очікуєте, що викликовий код буде ловити NPE окремо від IAE і робити щось інше? Чи намагаєтесь ви повідомити більш конкретне повідомлення про помилку? Але ви можете це зробити в тексті повідомлення про виключення, як і для всіх інших невірних параметрів.

По-четверте, всі інші невірні дані параметрів будуть IAE, так чому б не бути послідовними? Чому незаконний nullнастільки особливий, що заслуговує на окремий виняток від усіх інших видів незаконних аргументів?

Нарешті, я приймаю аргумент, наданий іншими відповідями про те, що частини Java API використовують NPE таким чином. Однак API Java не відповідає всім типам винятків до умовних імен, тому я думаю, що просто сліпо копіювати (вашу улюблену частину) Java API не є достатньо добрим аргументом, щоб обдурити ці інші міркування.


119
Пункт 60 ефективного Java 2-го видання: "Можливо, всі помилкові виклики методу зводяться до незаконного аргументу чи незаконного стану, але інші винятки стандартно використовуються для певних видів незаконних аргументів і станів. Якщо абонент передає нуль у певному параметрі, для якого нульові значення заборонені, конвенція наказує, що NullPointerException буде викинуто, а не IllegalArgumentException. Аналогічно, якщо абонент передає значення поза діапазоном у параметрі, що представляє собою індекс у послідовність, IndexOutOfBoundsException слід перекидати, а не IllegalArgumentException. "
Гілі

33
JavaDoc для NPE також констатує наступне: "Програми повинні викидати екземпляри цього класу, щоб вказати на інші незаконні використання нульового об'єкта." Це може бути більш зрозумілим :(
Р. Мартіньо Фернандес,

12
На жаль, методи перевірки Validate.notNull(commons lang) та Preconditions.checkNotNull(guava) обидва кидають NPE :-(
Aaron Digulla

2
Хоча у Guava також є Preconditions.checkArgument () кидає IllegalArgumentException ...
michaelok

16
@AaronDigulla, з документів Guava: "Ми розуміємо, що існує багато вагомих аргументів на користь того, щоб кинути IAE на нульовий аргумент. Насправді, якби у нас була машина часу, щоб повернутися назад> 15 років, ми могли б навіть спробувати підштовхнути речі Однак ми вирішили дотримуватися переваги JDK та ефективної Java NullPointerException. Якщо ви непохитні у своїй переконанні, що IAE має рацію, ви все одно маєте checkArgument(arg != null), просто без зручності повернення аргументу, або ви можете створити локальна утиліта для вашого проекту. " code.google.com/p/guava-libraries/wiki/IdeaGraveyard
Арто Бендікен

162

Стандарт - кинути своє NullPointerException. Загально непогрішна "Ефективна Java" коротко обговорює це в пункті 42 (перша редакція), пункт 60 (друга редакція) або пункт 72 (третя редакція) "Вигідне використання стандартних винятків":

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


95
Я категорично не згоден. NullPointerExceptions слід викидати лише у тому випадку, якщо JVM випадково дотримується нульової посилання. Саме ця різниця допомагає вам зателефонувати переглянути код о 3 ранку.
Thorbjørn Ravn Andersen

26
Я не обов'язково погоджуюся зі стандартом (я міг би насправді піти в будь-якому випадку з цього питання), але це ЯК, що є стандартним використанням у всій JDK, отже, Ефективна Java, що робить це для цього. Я думаю, що це випадок вибору того, чи слід слідувати стандарту, чи робити те, що ви вважаєте правильним. Якщо у вас немає дуже вагомих причин (а це, безумовно, може бути кваліфіковано), краще дотримуватися стандартної практики.
GaryF

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

8
Фантазії та софістика. Внизу MB пише: "Зауважте, що аргументи щодо жорсткої налагодження є неправдивими, тому що ви, звичайно, можете надати повідомлення NullPointerException, сказавши, що це було null, і чому воно не повинно бути null. Так само, як і в IllegalArgumentException."
Джим Балтер

10
Як початковий відповідь тут, дозвольте сказати, що це просто не так важливо. Це, звичайно, не гарантує 6 років розмови. Виберіть один, який вам подобається, і будьте послідовні. Стандарт, як я зазначив, - NPE. Якщо ви віддаєте перевагу IAE з будь-яких причин, займіться цим. Просто будьте послідовними.
GaryF

138

Я був всім прихильником кидання IllegalArgumentExceptionнульових параметрів, до сьогодні, коли я помітив java.util.Objects.requireNonNullметод у Java 7. За допомогою цього методу замість того, щоб робити:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

Ви можете зробити:

Objects.requireNonNull(param);

і він кине а, NullPointerExceptionякщо параметр, який ви його передаєте, є null.

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

Я думаю, що я вирішив у будь-якому випадку.

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

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


14
Гуава Preconditions.checkNotNull(arg)також кидає NPE.
assylias

14
Це насправді не додає більшої ваги NullPointerException для незаконних нульових аргументів. Як JDK RequNonNull (), так і Guava checkNotNull () можна викликати в будь-якому місці коду, будь-яким об'єктом. Наприклад, ви можете викликати їх всередині циклу. requNotNull () і checkNotNull () не могли припустити, що вони викликаються деякими аргументами методу і кидають IllegalArgumentException. Зауважте, що у Guava також є Preconditions.checkArgument (), який дійсно кидає IllegalArgumentException.
Богдан Кальмак

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

15
Я думаю, що JavaDoc з Object.requireNonNull () додає ваги аргументу: "Цей метод призначений головним чином для перевірки параметрів у методах та конструкторах"
Річард Зшеч

Майте на увазі, що аргумент ефективності на користь неявних нульових перевірок часто недійсний. JIT здатний розпізнавати нульові перевірки користувача та усунути наступні маються на увазі нульові перевірки та / або використовувати один і той же набір оптимізацій для будь-якого типу нульової перевірки. Дивіться цю вікі для отримання додаткової інформації, зокрема: Написані користувачем нульові перевірки в більшості випадків функціонально ідентичні тим, які вставлені JVM. Звичайно, якщо ви робите щось більш фантазійне у вашій нульовій формі, як власні повідомлення, ця оптимізація може не застосовуватися.
BeeOnRope

70

Я схильний дотримуватися дизайну бібліотек JDK, особливо колекцій та одночасності (Джошуа Блох, Дуг Лі, ті хлопці знають, як створити надійні API). Так чи інакше, багато API в JDK про-активно кидається NullPointerException.

Наприклад, Javadoc для Map.containsKeyдержав:

@throws NullPointerException, якщо ключ недійсний, і ця карта не дозволяє нульові ключі (необов’язково).

Цілком справедливо кинути власний NPE. Конвенція полягає в тому, щоб включити ім'я параметра, яке було нульовим, у повідомленні про виняток.

Шаблон іде:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

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


3
Їжа для роздумів: Можливо, причиною того, що NullPointerException не поширює IllegalArgumentException, є те, що перше може виникати у випадках, що не містять аргументів методу.
Гілі

2
@Gili: можливо, ця проблема існує в першу чергу, оскільки Java не підтримує багаторазове успадкування. Якщо Java підтримує MI, ви зможете викинути виняток, який успадковується як від IllegalArgumentException, так і від NullPointerException.
Лі Лі Раян

7
Повідомлення не повинно включати аргументи, оскільки воно завжди було б недійсним, даючи: "null не повинно бути null", не дуже корисно. :-) В іншому випадку я згоден, ви можете зробити "багатий" NPE, зі змістовним повідомленням.
PhiLho

5
Я повинен погодитися - дотримуйтесь стандартного API, коли сумніваєтесь. Не все в API оптимально для вас, але все ж його підтримують і повторюють сотні розробників і використовують мільйони програмістів. Тепер у Java 7 є ще один приклад використання NPE, який використовується таким чином; метод Objects.requireNonNull (T obj) - чітко визначений для перевірки того, що посилання на об'єкт є ненульовим, чітко вказаний для виконання перевірки параметрів у методах / конструкторах, і чітко вказаний для кидання NPE, якщо об'єкт є нульовим. Кінець
flamming_python

44

Проголосував аргумент Джейсона Коена, оскільки він був добре представлений. Дозвольте мені розчленувати це крок за кроком. ;-)

  • NPE JavaDoc прямо говорить, «інші незаконне використання об'єкта нульовий» . Якби це було лише обмеження ситуацій, коли час виконання зустрічається з нулем, коли цього не слід, усі такі випадки можна було б визначити набагато коротше.

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

  • Я б обрав NPE над IAE з кількох причин

    • Він більш конкретний щодо характеру незаконної операції
    • Логіка, яка помилково дозволяє нулю, має тенденцію сильно відрізнятися від логіки, яка помилково допускає незаконні значення. Наприклад, якщо я перевіряю дані, введені користувачем, якщо я отримую неприйнятне значення, джерелом цієї помилки є кінцевий користувач програми. Якщо я отримаю нуль, це помилка програміста.
    • Недійсні значення можуть спричинити такі речі, як переповнення стека, помилки в пам'яті, винятки для розбору і т. Д. Дійсно, більшість помилок, як правило, в деякий момент є недійсним значенням у виклику методу. З цієї причини я бачу IAE як НАЙБІЛЬШЕ ЗАГАЛЬНІСТЬ усіх винятків під RuntimeException.
  • Власне, інші недійсні аргументи можуть спричинити за собою всі інші винятки. UnknownHostException , FileNotFoundException , різноманітні винятки з помилок синтаксису, IndexOutOfBoundsException , збої аутентифікації тощо, тощо.

Взагалі, я вважаю, що NPE сильно злісний, тому що традиційно асоціюється з кодом, який не дотримується принципу невдачі . Це, плюс неспроможність JDK заповнити NPE рядком повідомлення, справді створило сильні негативні настрої, які недостатньо обґрунтовані. Дійсно, різниця між NPE та IAE з точки зору виконання - це суто назва. З цього погляду, чим точніше ви ставитеся до імені, тим більше ясності ви надаєте абоненту.


Різниця між більшістю неперевірених винятків - це лише назва.
Thorbjørn Ravn Andersen

20

Це питання стилю "Священної війни". Іншими словами, обидві альтернативи хороші, але люди матимуть свої переваги, які вони захищатимуть до смерті.


Ні, є лише одна правильна відповідь на це запитання, і це використовувати виняток кидання IllegalArgument, коли введення методу невірно. Також у середовищі розробників ви можете використовувати твердження, щоб перевірити достовірність вводу та викинути належне виключення;)
Mr.Q

@ Mr.Q І я думаю, що це NullPointerExceptionслід кинути: це конвенція, яку JDK використовує та вимагає для інтерфейсів, вона більш конкретна (як IndexOutOfBoundsExceptionі т.д.) тощо.
Соломон Учко

kekekekkek ...: D
Yousha Aleayoub

17

Якщо це setterметод і nullпередається йому, я думаю, було б більше сенсу кинути IllegalArgumentException. NullPointerException, Здається, більше сенсу в тому випадку , коли ви намагаєтеся насправді використовувати null.

Таким чином, якщо ви використовуєте його , і це null, NullPointer. Якщо він передається в і це null, IllegalArgument.


9

Apache Commons Lang має NullArgumentException, який виконує ряд речей, обговорених тут: він розширює IllegalArgumentException, і його єдиний конструктор приймає назву аргументу, який повинен був бути недійсним.

Хоча я вважаю, що кидаючи щось на зразок NullArgumentException або IllegalArgumentException більш точно описує виняткові обставини, ми з колегами вирішили звернутися до порад Блоха з цього приводу.


7
Зауважте, вони видалили його з commons-lang3: apache-commons.680414.n4.nabble.com/…
artbristol

7

Не міг більше погодитися з тим, що говориться. Невдача рано, невдача швидко. Досить гарна мантра винятку.

Питання про те, який Виняток кинути - це здебільшого питання особистого смаку. На мій погляд, IllegalArgumentException здається більш специфічним, ніж використання NPE, оскільки він говорить мені, що проблема була в аргументі, який я передав методу, а не зі значенням, яке може бути сформовано під час виконання методу.

Мої 2 центи


7

Насправді, питання про те, щоб кинути IllegalArgumentException або NullPointerException, на мій скромний погляд, є лише «святою війною» для меншості з неповноцінним розумінням поводження з винятками на Java. Загалом, правила прості та такі:

  • Порушення обмеження аргументу повинні бути вказані якомога швидше (-> швидкий збій), щоб уникнути незаконних станів, які набагато важче налагодити
  • у випадку недійсного нульового покажчика з будь-якої причини киньте NullPointerException
  • у випадку незаконного індексу масиву / колекції, киньте ArrayIndexOutOfBounds
  • у разі негативного розміру масиву / колекції, киньте NegativeArraySizeException
  • у разі неправомірного аргументу, який не охоплений вище, і для якого у вас немає іншого більш конкретного винятку, киньте IllegalArgumentException як кошик для сміття
  • з іншого боку, у випадку порушення обмежень у ПОЛІ, яке не вдалося уникнути швидким збоєм з якихось поважних причин, ловіть і повторно скидайте як IllegalStateException або більш конкретний перевірений виняток. Ніколи не дозволяйте в цьому випадку передавати оригінальні NullPointerException, ArrayIndexOutOfBounds тощо!

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

(1) Програміст не може з упевненістю припустити, що всі випадки порушення обмежень аргументів призводять до IllegalArgumentException, оскільки велика більшість стандартних класів використовують цей виняток, а не як кошик для відходів, якщо немає більш конкретного виду виключень. Спроба відобразити всі випадки порушення обмежень аргументів на IllegalArgumentException у вашому API лише призводить до розчарування програміста з використанням ваших класів, оскільки стандартні бібліотеки здебільшого дотримуються різних правил, які порушують ваші, і більшість ваших користувачів API також використовуватимуть їх!

(2) Зображення винятків насправді призводить до різного роду аномалії, спричиненої єдиним успадкуванням: Усі винятки Java є класами, а тому підтримують лише єдине успадкування. Отже, не існує способу створити виняток, який справді кажуть і NullPointerException, і IllegalArgumentException, оскільки підкласи можуть успадковувати лише те чи інше. Закидання IllegalArgumentException у разі нульового аргументу, таким чином, користувачам API важче розрізняти проблеми, коли програма намагається програматично виправити проблему, наприклад, подаючи значення за замовчуванням у повтор виклику!

(3) Картографування фактично створює небезпеку маскування помилок. Для того, щоб відобразити порушення обмеження аргументів у IllegalArgumentException, вам потрібно буде кодувати зовнішній пробний прийом у кожному методі, який має обмежені аргументи. Однак просто ловити RuntimeException у цьому блоці вилову не виникає сумніву, оскільки це ризикує відображенням документованих RuntimeExceptions, кинутих методами libery, які використовуються у вашій формі, у IllegalArgumentException, навіть якщо вони не викликані порушеннями обмеження аргументів. Тож вам потрібно бути дуже конкретним, але навіть ці зусилля не захищають вас від випадків, коли ви випадково відобразите недокументований виняток виконання іншого API (тобто помилку) в IllegalArgumentException свого API.

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


6

Прийнята практика, якщо використовувати IllegalArgumentException (String message), щоб визначити параметр недійсним і дати якомога більше деталей ... Отже, щоб сказати, що параметри були визнані недійсними, а виняток - ненульним, ви б щось зробили подобається це:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

У вас практично немає причин неявно використовувати "NullPointerException". NullPointerException - це виняток, викинутий віртуальною машиною Java при спробі виконання коду на нульовій посиланні (Like toString () ).


6

Викидання виключення, яке ексклюзивно для nullаргументів (незалежно від того, NullPointerExceptionчи спеціальний тип), робить автоматизоване nullтестування більш надійним. Це автоматизоване тестування може бути проведене з відображенням та набором значень за замовчуванням, як у Guava 's NullPointerTester. Наприклад, NullPointerTesterнамагатиметься викликати наступний метод ...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

... з двома списками аргументів: "", nullі null, ImmutableList.of(). Це дозволить перевірити, що кожен із цих дзвінків кидає очікуване NullPointerException. Для цієї реалізації проходження nullсписку не дає NullPointerException. Однак, трапляється, створюється, IllegalArgumentExceptionоскільки NullPointerTesterтрапляється використовувати рядок за замовчуванням "". Якщо NullPointerTesterочікує лише NullPointerExceptionна nullзначення, він ловить помилку. Якщо вона очікує IllegalArgumentException, вона її сумує.


5

Деякі колекції припускають, що nullвін відхилений, NullPointerExceptionа не IllegalArgumentException. Наприклад, якщо порівнювати набір, що містить nullнабір, який відхиляє null, перший набір зателефонує containsAllна другий і вловить його NullPointerException- але ні IllegalArgumentException. (Я дивлюся на реалізацію AbstractSet.equals.)

Ви можете обґрунтовано стверджувати, що використання неперевірених винятків таким чином є антипаттерном, що порівнювати колекції, що містять nullколекції, які не можуть містити, nullє ймовірною помилкою, яка справді повинна створити виняток, або що nullвзагалі внесення колекції є поганою ідеєю . Тим не менше, якщо ви не хочете сказати, що equalsв такому випадку викинете виняток, ви запам'ятаєте, що NullPointerExceptionпотрібно в певних обставинах, а не в інших. ("IAE перед NPE, за винятком після" c "...")


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

2
new TreeSet<>().containsAll(Arrays.asList((Object) null));кидає, NPEтому що Listмістить null.
Кріс Повірк

1
Так, TreeSet # містить кидки NPE, "якщо вказаний елемент є нульовим і цей набір використовує природне впорядкування, або його компаратор не дозволяє нульових елементів". Подивився тільки на AbstractSet, який дозволяє зробити null, моє погано. Особисто мені здається дивним, що він не просто повертає помилкове значення, оскільки в такому випадку не може бути додано нуль.
Alowaniak

5

Як суб'єктивне питання це слід закрити, але оскільки воно все ще відкрите:

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

NullPointerException: Не кидайте навмисно. NPE повинні бути викинуті тільки VM, коли винесе нульове посилання. Необхідно докласти всіх можливих зусиль для того, щоб вони ніколи не кидались. @Nullable і @NotNull слід використовувати разом з інструментами аналізу коду, щоб знайти ці помилки.

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

IllegalStateException: кидається, коли функція викликається і її аргументи є або несподіваними в момент їх передачі, або несумісні зі станом об'єкта, членом якого є метод.

Наприклад, існували дві внутрішні версії IndexOutOfBoundsException, використовувані в речах, що мають довжину. Один підклас IllegalStateException, який використовується, якщо індекс був більшим за довжину. Інший підклас IllegalArgumentException, який використовується, якщо індекс був від'ємним. Це було тому, що ви можете додати більше об'єктів до об'єкта, і аргумент буде дійсним, тоді як від'ємне число ніколи не є дійсним.

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

NullPointerException: Обробіть справу Null або поставте твердження, щоб NPE не кидався. Якщо ви ставите твердження, це лише один з двох інших типів. По можливості продовжуйте налагодження, як ніби твердження там було в першу чергу.

IllegalArgumentException: у вас на сайті виклику щось не так. Якщо передані значення є з іншої функції, з’ясуйте, чому ви отримуєте неправильне значення. Якщо ви передаєте в одному з своїх аргументів розповсюдження, помилка перевіряє стек виклику, поки ви не знайдете функцію, яка не повертає очікуване.

IllegalStateException: Ви не викликали свої функції у правильному порядку. Якщо ви використовуєте один із своїх аргументів, перевірте їх і киньте IllegalArgumentException, що описує проблему. Потім ви можете розповсюджувати щоки проти стека, поки не знайдете проблему.

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


4

Взагалі розробник ніколи не повинен кидати NullPointerException. Цей виняток кидається під час виконання програми, коли код намагається знеструмити змінну, значення якої є нульовою. Тому, якщо ваш метод хоче явно заборонити null, на відміну від просто того, що має нульове значення підняти NullPointerException, вам слід кинути IllegalArgumentException.


9
JavaDoc в NPE має іншу думку: "Програми повинні викидати екземпляри цього класу, щоб вказати на інші незаконні використання нульового об'єкта." Не будьте такі категоричні
Донз

4

Я хотів виділити Null аргументи з інших незаконних аргументів, тому я отримав виняток з IAE під назвою NullArgumentException. Навіть не потрібно читати повідомлення про виключення, я знаю, що нульовий аргумент передано у метод і, прочитавши повідомлення, я з’ясовую, який аргумент був недійсним. Я все ще ловлю NullArgumentException за допомогою обробника IAE, але в моїх журналах є те, де я швидко бачу різницю.


Я прийняв підхід "кинути новий IllegalArgumentException (" foo == null ")". У будь-якому випадку вам потрібно занотувати ім’я змінної (щоб бути впевненим, що ви дивитесь на правильну позицію тощо)
Thorbjørn Ravn Andersen

4

дихотомія ... Вони не перетинаються? Тільки неперекриваються частини цілого можуть скласти дихотомію. Як я бачу це:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

1
Це вдвічі збільшить накладні витрати на створення виключень і насправді не допоможе, оскільки ловля NullPointerExceptionнічого не зробить. Єдине, що могло б допомогти, це те IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, що у нас немає багаторазового успадкування.
maaartinus

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

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

4

NullPointerExceptionкидається при спробі отримати доступ до об'єкта з довідковою змінною, поточне значення якої становить null.

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


3

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


0

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


-1

Визначення із посилань на два винятки вище: IllegalArgumentException: Кинуто, щоб вказати на те, що методу було передано незаконний або невідповідний аргумент. NullPointerException: кидається, коли програма намагається використовувати null у випадку, коли потрібен об'єкт.

Велика різниця тут полягає в тому, що IllegalArgumentException повинен використовуватися при перевірці того, що аргумент для методу є дійсним. NullPointerException повинен використовуватися, коли об'єкт "використовується", коли він є нульовим.

Я сподіваюся, що це допоможе поставити обох у перспективу.


1
Важливим бітом є те, що саме програма використовує null, а не час виконання. Таким чином, існує досить велике перекриття між "коли методом було передано незаконний або невідповідний аргумент" і "коли в додатку використовується null". Теоретично, якщо додаток передає нуль для поля, яке вимагає ненульового значення, обидва критерії виконуються.
Крістофер Сміт

-1

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

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

Якщо я переосмислюю метод, я використовую той, що використовується метод переопределення.


-1

Вам слід кинути IllegalArgumentException, оскільки це дасть зрозуміти програмісту, що він зробив щось недійсне. Розробники настільки звикли бачити NPE, кинуту VM, що будь-який програміст не одразу усвідомить свою помилку, і почне оглядатись навмання, або ще гірше, звинувачує ваш код у тому, що він "баггі".


4
Вибачте, якщо програміст озирається "випадковим чином" після отримання будь-якого винятку ... зміна імені виключення не допоможе багато.
Крістофер Сміт

-1

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

GaryF і tweakt відкинули "Ефективну Java" (яку я клянусь) посиланнями, які рекомендує використовувати NPE. А дивлячись на те, як побудовані інші хороші API - це найкращий спосіб зрозуміти, як створити API.

Ще один хороший приклад - подивитися на API API Spring. Наприклад, org.springframework.beans.BeanUtils.instantiateClass (конструктор ctor, Object [] аргументи) має рядок Assert.notNull (ctor, "Конструктор не повинен бути нульовим"). org.springframework.util.Assert.notNull (Object object, String message) метод перевіряє, чи є переданий аргумент (об'єкт) нульовим, і якщо він передає нове IllegalArgumentException (повідомлення), яке потім потрапляє в org. метод springframework.beans.BeanUtils.instantiateClass (...).


-5

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


Звичайний час запуску включає змістовний msg.
мП.

Насправді цей коментар міг би отримати іншу думку. Нехай ВМ виступає NPEще програмісти, IAEякщо вони хочуть, виступають перед ВМ.
Джин Квон

1
Дорогий? Я не думаю, що == null - це так дорого ... Окрім того, аргумент null може бути просто збережено для останнього використання, і він викине виняток задовго після виклику методу, зробивши помилку важче відстежувати. Або ви можете створити дорогий об’єкт перед тим, як використовувати аргумент null тощо. Раннє виявлення здається хорошим варіантом.
PhiLho

вниз голосування цієї відповіді - це нерозуміння апаратних засобів, що стоять позаду. Звичайно ж, апаратні перевірки (що робить ЦП) дешевші, ніж явна перевірка. Перенаправлення нуля - це особливий випадок SegmentationFault (SegV) (доступ до сторінки, яка не належить процесу), яка CPU / OS перевіряє, а JRE обробляє як особливий випадок, що кидає NullPointerException.
digital_infinity
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.