IllegalArgumentException o NullPointerException per un parametro null? [chiuso]


547

Ho un metodo setter semplice per una proprietà e nullnon è appropriato per questa particolare proprietà. Sono sempre stato strappato in questa situazione: dovrei lanciare un IllegalArgumentException, o un NullPointerException? Dai javadocs, entrambi sembrano appropriati. Esiste una sorta di standard compreso? O è solo una di quelle cose che dovresti fare come preferisci ed entrambe sono davvero corrette?

Risposte:


299

Sembra che IllegalArgumentExceptionsia richiesto se non si desidera nullessere un valore consentito e NullPointerExceptionverrebbe generato se si stesse tentando di utilizzare una variabile che risulta essere null.


33
Le seguenti risposte a questa domanda fanno argomentazioni convincenti che NullPointerException sia l'eccezione corretta: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; e stackoverflow.com/a/6358/372926 .
SamStephens,

2
IllegalArgumentExceptionè in contraddizione con Java's Objects.requireNonNull (T) e Guava's Preconditions.checkNotNull (T) che genera a NullPointerException. Tuttavia, la risposta giusta è definitivamente IllegalArgumentException come spiegato nella risposta eccellente di Jason Cohen e nella sua sezione commenti .
matoni,

417

Dovresti usare IllegalArgumentException(IAE), non NullPointerException(NPE) per i seguenti motivi:

Innanzitutto, JavaDoc di NPE elenca esplicitamente i casi in cui è appropriato NPE. Si noti che tutti vengono generati dal runtime quando nullvengono utilizzati in modo inappropriato. Al contrario, IAE JavaDoc non potrebbe essere più chiaro: "Lanciato per indicare che un metodo è stato superato un argomento illegale o inappropriato". Sì, sei tu!

Secondo, quando vedi un NPE in una traccia dello stack, cosa pensi? Probabilmente qualcuno ha fatto riferimento a null. Quando vedi IAE, supponi che il chiamante del metodo nella parte superiore dello stack abbia passato un valore illegale. Ancora una volta, quest'ultima ipotesi è vera, la prima è fuorviante.

In terzo luogo, poiché IAE è chiaramente progettato per la convalida dei parametri, è necessario assumerlo come scelta predefinita di eccezione, quindi perché scegliere invece NPE? Certamente non per un comportamento diverso - ti aspetti davvero che il codice chiamante rilevi gli NPE separatamente dall'IAE e di conseguenza faccia qualcosa di diverso? Stai cercando di comunicare un messaggio di errore più specifico? Puoi comunque farlo nel testo del messaggio di eccezione, come dovresti fare per tutti gli altri parametri errati.

In quarto luogo, tutti gli altri dati di parametri errati saranno IAE, quindi perché non essere coerenti? Perché un illegale nullè così speciale da meritare un'eccezione separata da tutti gli altri tipi di argomenti illegali?

Infine, accetto l'argomento fornito da altre risposte secondo cui parti dell'API Java utilizzano NPE in questo modo. Tuttavia, l'API Java non è coerente con tutto, dai tipi di eccezione alle convenzioni di denominazione, quindi penso che copiare semplicemente alla cieca (la tua parte preferita) l'API Java non sia un argomento abbastanza valido per superare queste altre considerazioni.


120
Efficace Java 2nd Edition, Item 60: "Probabilmente, tutte le invocazioni di metodi errate si riducono a un argomento illegale o uno stato illegale, ma altre eccezioni vengono normalmente utilizzate per alcuni tipi di argomenti e stati illegali. Se un chiamante passa null in alcuni parametri per i quali valori nulli sono proibiti, la convenzione impone che venga lanciata NullPointerException anziché IllegalArgumentException. Allo stesso modo, se un chiamante passa un valore fuori range in un parametro che rappresenta un indice in una sequenza, si dovrebbe lanciare IndexOutOfBoundsException anziché IllegalArgumentException. "
Gili,

33
JavaDoc per NPE afferma inoltre quanto segue: "Le applicazioni devono generare istanze di questa classe per indicare altri usi illegali dell'oggetto null." Questo potrebbe essere più chiaro :(
R. Martinho Fernandes il

12
Sfortunatamente, i metodi di validazione Validate.notNull(commons lang) e Preconditions.checkNotNull(guava) lanciano entrambi NPE :-(
Aaron Digulla,

2
Anche se Guava ha anche Preconditions.checkArgument () genera IllegalArgumentException ...
michaelok il

16
@AaronDigulla, dai documenti di Guava: "Ci rendiamo conto che ci sono molti validi argomenti a favore del lancio di IAE su un argomento nullo. In effetti, se avessimo una macchina del tempo per tornare indietro> 15 anni, potremmo persino provare a spingere le cose dentro quella direzione, tuttavia, abbiamo deciso di attenerci alla preferenza JDK e Java effettiva di NullPointerException. Se sei fermamente convinto che IAE sia giusto, lo hai ancora fatto checkArgument(arg != null), senza la comodità di restituire arg, oppure puoi creare un'utilità locale per il tuo progetto ". code.google.com/p/guava-libraries/wiki/IdeaGraveyard
Arto Bendiken,

162

Lo standard è di lanciare NullPointerException. La "Effective Java" generalmente infallibile ne discute brevemente nell'articolo 42 (prima edizione), nell'articolo 60 (seconda edizione) o nell'articolo 72 (terza edizione) "Favorire l'uso delle eccezioni standard":

"Probabilmente, tutte le invocazioni di metodi errati si riducono a un argomento o stato illegale, ma altre eccezioni vengono normalmente utilizzate per alcuni tipi di argomenti e stati illegali. Se un chiamante passa null in alcuni parametri per i quali sono vietati i valori null, la convenzione impone che NullPointerException deve essere generato anziché IllegalArgumentException. "


95
Sono fortemente in disaccordo. NullPointerExceptions deve essere generato solo se la JVM segue accidentalmente un riferimento null. Questa è la differenza che ti aiuta quando viene chiamato per vedere il codice alle 3 del mattino.
Thorbjørn Ravn Andersen,

26
Non sono necessariamente d'accordo con lo standard (potrei effettivamente andare in entrambi i modi sul problema), ma è quello che è l'uso standard in tutto il JDK, quindi efficace Java fa il caso. Penso che questo sia il caso di scegliere se seguire o meno lo standard o fare la cosa che ritieni giusta. A meno che tu non abbia una buona ragione (e questo certamente può qualificarsi), è meglio seguire la pratica standard.
GaryF,

21
La traccia dell'eccezione mostra il punto dell'eccezione, quindi se la differenza nel tipo di eccezione causa l'inferno per te o è "la differenza che ti aiuta", stai facendo qualcosa di molto sbagliato.
Jim Balter,

8
Fantasie e sofismi. Di seguito, MB scrive "Nota che gli argomenti sul debug hard sono falsi perché puoi ovviamente fornire un messaggio a NullPointerException dicendo che era nullo e perché non dovrebbe essere nullo. Proprio come con IllegalArgumentException."
Jim Balter,

10
Come risponditore originale qui, lasciami dire che non importa così tanto. Certamente non garantisce 6 anni di conversazione. Scegline uno, come preferisci e sii coerente. Lo standard, come ho sottolineato, è NPE. Se preferisci IAE per qualsiasi motivo, provaci. Sii coerente.
GaryF,

138

Ero tutto a favore del lancio IllegalArgumentExceptiondi parametri null, fino ad oggi, quando ho notato il java.util.Objects.requireNonNullmetodo in Java 7. Con quel metodo, invece di fare:

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

tu puoi fare:

Objects.requireNonNull(param);

e lancerà a NullPointerExceptionse il parametro che passi è null.

Dato che quel metodo è proprio nel bel mezzo di java.utilme prendo la sua esistenza per essere un'indicazione abbastanza forte che lanciare NullPointerExceptionè "il modo Java di fare le cose".

Penso di essere deciso in ogni caso.

Si noti che gli argomenti sul debug hard sono falsi perché è possibile ovviamente fornire un messaggio per NullPointerExceptiondire cosa era null e perché non dovrebbe essere null. Proprio come con IllegalArgumentException.

Un ulteriore vantaggio NullPointerExceptionè che, in un codice critico ad alte prestazioni, è possibile rinunciare a un controllo esplicito per null (e a NullPointerExceptioncon un messaggio di errore amichevole) e fare semplicemente affidamento su ciò che NullPointerExceptionsi ottiene automaticamente quando si chiama un metodo sul null parametro. A condizione che tu chiami un metodo rapidamente (cioè fallisci velocemente), hai essenzialmente lo stesso effetto, ma non è così facile da usare per lo sviluppatore. La maggior parte delle volte è probabilmente meglio controllare esplicitamente e lanciare con un messaggio utile per indicare quale parametro era nullo, ma è bello avere la possibilità di cambiarlo se le prestazioni dettano senza rompere il contratto pubblicato del metodo / costruttore.


14
Guava Preconditions.checkNotNull(arg)lancia anche NPE.
Assylias,

14
Questo non sta davvero aggiungendo più peso a NullPointerException per ARGUMENTI null illegali. Sia JDK requestNonNull () che Guava checkNotNull () possono essere richiamati in qualsiasi punto del codice, con qualsiasi oggetto. Potresti chiamarli all'interno di un loop per esempio. requireNotNull () e checkNotNull () non potevano presumibilmente essere invocati con alcuni argomenti del metodo e lanciare IllegalArgumentException. Nota che Guava ha anche Preconditions.checkArgument () che genera IllegalArgumentException.
Bogdan Calmac,

2
Un punto equo di Bogdan, anche se sospetto che l'uso tipico (e generalmente previsto) di requestNonNull sia per il controllo degli argomenti. Se avessi bisogno di verificare che qualcosa non fosse nullo in un ciclo, avrei pensato che un'asserzione sarebbe il modo tipico.
MB.

15
Penso che JavaDoc di Object.requireNonNull () aggiunga peso all'argomento: "Questo metodo è progettato principalmente per eseguire la convalida dei parametri in metodi e costruttori"
Richard Zschech,

Tenere presente che l'argomento prestazioni a favore di controlli nulli impliciti è spesso non valido. JIT è in grado di riconoscere i controlli null dell'utente ed eludere il seguente controllo null implicito e / o utilizzare la stessa serie di ottimizzazioni su entrambi i tipi di controllo null. Vedi questa wiki per maggiori informazioni, in particolare: I controlli null scritti dall'utente sono nella maggior parte dei casi funzionalmente identici a quelli inseriti dalla JVM. Naturalmente, se stai facendo qualcosa di più elaborato nel tuo null come messaggi personalizzati, questa ottimizzazione potrebbe non essere applicabile.
BeeOnRope,

70

Tendo a seguire il design delle librerie JDK, in particolare Collezioni e concorrenza (Joshua Bloch, Doug Lea, quei ragazzi sanno come progettare solide API). Comunque, molte API nel JDK lanciano proattivamente NullPointerException.

Ad esempio, Javadoc per gli Map.containsKeystati:

@throws NullPointerException se la chiave è null e questa mappa non consente le chiavi null (opzionale).

È perfettamente valido lanciare il proprio NPE. La convenzione deve includere il nome del parametro che era nullo nel messaggio dell'eccezione.

Lo schema va:

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

Qualunque cosa tu faccia, non consentire a un valore errato di essere impostato e generare un'eccezione in seguito quando altri codici tentano di utilizzarlo. Questo rende il debug un incubo. Dovresti sempre seguire il principio "fail-fast".


3
Spunti di riflessione: forse il motivo per cui NullPointerException non estende IllegalArgumentException è che il primo può verificarsi in casi che non riguardano argomenti del metodo.
Gili,

2
@Gili: forse questo problema esiste in primo luogo perché Java non supporta l'ereditarietà multipla. Se Java supporta MI, si sarebbe in grado di generare un'eccezione che eredita da IllegalArgumentException e NullPointerException.
Lie Ryan

7
Il messaggio non deve includere l'argomento, poiché sarebbe sempre nullo, dando: "null non deve essere nullo", non molto utile. :-) Altrimenti, sono d'accordo, puoi creare un NPE "ricco", con un messaggio significativo.
PhiLho,

5
Devo essere d'accordo: seguire l'API standard in caso di dubbi. Non tutto nell'API è ottimale, ma è comunque gestito e ripetuto da centinaia di sviluppatori e utilizzato da milioni di programmatori. Ora in Java 7 abbiamo un altro esempio dell'NPE utilizzato in questo modo; il metodo Objects.requireNonNull (T obj) - chiaramente specificato per verificare che i riferimenti agli oggetti siano non nulli, chiaramente specificato per eseguire la convalida dei parametri in metodi / costruttori e chiaramente specificato per lanciare un NPE se l'oggetto è nullo. Fine di
flamming_python il

44

Votano l'argomento di Jason Cohen perché è stato ben presentato. Fammi smembrare passo dopo passo. ;-)

  • L' NPE JavaDoc dice esplicitamente "altri usi illegali dell'oggetto null" . Se fosse limitato alle situazioni in cui il runtime incontra un valore nullo quando non dovrebbe, tutti questi casi potrebbero essere definiti in modo molto più succinto.

  • Non puoi farne a meno se ritieni che la cosa sia sbagliata, ma supponendo che l'incapsulamento sia applicato correttamente, non dovresti davvero preoccuparti o notare se un null è stato erroneamente notificato contro se un metodo ha rilevato un null inappropriato e ha generato un'eccezione.

  • Sceglierei NPE su IAE per diversi motivi

    • È più specifico sulla natura dell'operazione illegale
    • La logica che consente erroneamente i null tende ad essere molto diversa dalla logica che consente erroneamente valori illegali. Ad esempio, se sto convalidando i dati immessi da un utente, se ottengo un valore inaccettabile, l'origine di tale errore è con l'utente finale dell'applicazione. Se ricevo un valore null, si tratta dell'errore del programmatore.
    • Valori non validi possono causare cose come overflow dello stack, errori di memoria insufficiente, analisi delle eccezioni, ecc. In effetti, la maggior parte degli errori si presenta generalmente, ad un certo punto, come valore non valido in una chiamata di metodo. Per questo motivo, vedo IAE come il più GENERALE di tutte le eccezioni in RuntimeException.
  • In realtà, altri argomenti non validi possono comportare tutti i tipi di altre eccezioni. UnknownHostException , FileNotFoundException , varie eccezioni di errori di sintassi, IndexOutOfBoundsException , errori di autenticazione, ecc., Ecc.

In generale, ritengo che l'NPE sia molto diffamato perché tradizionalmente è stato associato a un codice che non segue il principio del fallimento rapido . Ciò, oltre all'incapacità del JDK di popolare gli NPE con una stringa di messaggi, ha davvero creato un forte sentimento negativo che non è fondato. In effetti, la differenza tra NPE e IAE da una prospettiva di runtime è strettamente il nome. Da quella prospettiva, più preciso sei con il nome, più chiarezza dai al chiamante.


La differenza tra le eccezioni più deselezionate è solo il nome.
Thorbjørn Ravn Andersen,

20

È una domanda in stile "Holy War". In altre parole, entrambe le alternative sono buone, ma le persone avranno le loro preferenze che difenderanno fino alla morte.


No, c'è solo una risposta giusta a questa domanda e quella è usare l'eccezione IllegalArgument quando l'input al metodo non è corretto. Anche in ambiente di sviluppo, è possibile utilizzare le asserzioni per verificare la validità dell'input e generare un'eccezione adeguata;)
Mr.Q

@ Mr.Q E penso che NullPointerExceptiondovrebbe essere lanciato: è la convenzione utilizzata dal JDK e richiede interfacce, è più specifica (proprio come IndexOutOfBoundsException, ecc.), Ecc.
Solomon Ucko,

kekekekkek ...: D
Yousha Aleayoub

17

Se è un settermetodo e nullviene passato ad esso, penso che avrebbe più senso lanciarne uno IllegalArgumentException. A NullPointerExceptionsembra avere più senso nel caso in cui si stia tentando di utilizzare effettivamente null.

Quindi, se si sta utilizzando e che è null, NullPointer. Se è stata passata in ed è null, IllegalArgument.


9

Apache Commons Lang ha una NullArgumentException che fa alcune delle cose discusse qui: estende IllegalArgumentException e il suo unico costruttore prende il nome dell'argomento che avrebbe dovuto essere non nullo.

Mentre ritengo che lanciare qualcosa come NullArgumentException o IllegalArgumentException descriva più accuratamente le circostanze eccezionali, io e i miei colleghi abbiamo scelto di rimandare al consiglio di Bloch sull'argomento.


7
Nota che l'hanno rimosso da commons-lang3: apache-commons.680414.n4.nabble.com/…
artbristol

7

Non potrei essere più d'accordo con ciò che viene detto. Fallire presto, fallire velocemente. Mantra d'eccezione abbastanza buono.

La domanda su quale eccezione lanciare è principalmente una questione di gusti personali. Nella mia mente IllegalArgumentException sembra più specifico dell'utilizzo di un NPE poiché mi sta dicendo che il problema era dovuto a un argomento che ho passato al metodo e non a un valore che potrebbe essere stato generato durante l'esecuzione del metodo.

I miei 2 centesimi


7

In realtà, la questione di lanciare IllegalArgumentException o NullPointerException è a mio modesto punto di vista solo una "guerra santa" per una minoranza con una comprensione incompleta della gestione delle eccezioni in Java. In generale, le regole sono semplici e come segue:

  • le violazioni dei vincoli di argomento devono essere indicate il più rapidamente possibile (-> errore rapido), al fine di evitare stati illegali che sono molto più difficili da eseguire il debug
  • in caso di un puntatore null non valido per qualsiasi motivo, genera NullPointerException
  • nel caso di un indice array / raccolta illegale, genera ArrayIndexOutOfBounds
  • in caso di dimensioni di array / raccolta negative, generare NegativeArraySizeException
  • nel caso di un argomento illegale non coperto da quanto sopra e per il quale non si dispone di un altro tipo di eccezione più specifico, gettare IllegalArgumentException come cestino
  • d'altra parte, in caso di violazione di un vincolo ENTRO UN CAMPO che non poteva essere evitato in caso di errore rapido per qualche motivo valido, catturare e ricominciare come IllegalStateException o un'eccezione controllata più specifica. Non lasciare mai passare l'originale NullPointerException, ArrayIndexOutOfBounds, ecc. In questo caso!

Ci sono almeno tre ottime ragioni contro il caso di mappare tutti i tipi di violazioni dei vincoli degli argomenti a IllegalArgumentException, con il terzo probabilmente essere così grave da contrassegnare lo stile scorretto della pratica:

(1) Un programmatore non può presumere in modo sicuro che tutti i casi di violazione dei vincoli degli argomenti generino IllegalArgumentException, poiché la grande maggioranza delle classi standard utilizza questa eccezione piuttosto come cestino se non è disponibile un tipo più specifico di eccezione. Cercare di mappare tutti i casi di violazioni dei vincoli degli argomenti a IllegalArgumentException nella tua API porta solo alla frustrazione del programmatore che utilizza le tue classi, poiché le librerie standard seguono principalmente regole diverse che violano le tue e anche la maggior parte dei tuoi utenti API le utilizzerà!

(2) La mappatura delle eccezioni comporta in realtà un diverso tipo di anomalia, causata da una singola eredità: tutte le eccezioni Java sono classi e quindi supportano solo la singola eredità. Pertanto, non esiste alcun modo per creare un'eccezione che sia in realtà sia una NullPointerException che una IllegalArgumentException, poiché le sottoclassi possono ereditare solo dall'una o dall'altra. Lanciare un'eccezione IllegalArgumentException in caso di argomento null rende quindi più difficile per gli utenti API distinguere i problemi ogni volta che un programma tenta di correggere programmaticamente il problema, ad esempio inserendo valori predefiniti in una ripetizione di chiamata!

(3) La mappatura in realtà crea il pericolo del mascheramento dei bug: al fine di mappare le violazioni dei vincoli degli argomenti in IllegalArgumentException, è necessario codificare un try-catch esterno all'interno di ogni metodo che abbia argomenti vincolati. Tuttavia, catturare semplicemente RuntimeException in questo blocco catch è fuori discussione, perché questo rischia di mappare RuntimeExceptions documentate generate dai metodi di libery utilizzati all'interno dei tuoi in IllegalArgumentException, anche se non sono causate da violazioni dei vincoli degli argomenti. Quindi devi essere molto specifico, ma anche quello sforzo non ti protegge dal caso in cui accidentalmente mappi un'eccezione di runtime non documentata di un'altra API (cioè un bug) in un'eccezione IllegalArgumentException della tua API.

D'altra parte, con la pratica standard, le regole restano semplici e le cause di eccezione rimangono non mascherate e specifiche. Per il metodo chiamante, anche le regole sono semplici: - se si riscontra un'eccezione di runtime documentata di qualsiasi tipo perché si è passato un valore illegale, ripetere la chiamata con un valore predefinito (per questo specifiche eccezioni sono necessarie) o correggere il codice - se invece si riscontra un'eccezione di runtime che non è documentata per un determinato insieme di argomenti, presentare una segnalazione di bug ai produttori del metodo per assicurarsi che il loro codice o la loro documentazione siano corretti.


6

La pratica accettata se usare IllegalArgumentException (messaggio String) per dichiarare un parametro non valido e fornire il maggior numero possibile di dettagli ... Quindi, per dire che un parametro è stato trovato nullo mentre l'eccezione non è nulla, si dovrebbe fare qualcosa come questo:

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

Non hai praticamente alcun motivo per utilizzare implicitamente "NullPointerException". NullPointerException è un'eccezione generata dalla Java Virtual Machine quando si tenta di eseguire il codice su riferimento null (Like toString () ).


6

Il lancio di un'eccezione esclusiva degli nullargomenti (indipendentemente dal tipo NullPointerExceptiono personalizzato) rende i nulltest automatizzati più affidabili. Questo test automatici può essere fatto con la riflessione e un insieme di valori di default, come nel Guava s' NullPointerTester. Ad esempio, NullPointerTestertenterebbe di chiamare il seguente metodo ...

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

... con due elenchi di argomenti: "", nulle null, ImmutableList.of(). Verificherebbe che ciascuna di queste chiamate genera l'atteso NullPointerException. Per questa implementazione, il passaggio di un nullelenco non produce NullPointerException. Capita, tuttavia, di produrre un IllegalArgumentExceptionperché NullPointerTestercapita di usare una stringa predefinita di "". Se NullPointerTestersi aspetta solo NullPointerExceptiondi nullvalori, cattura il bug. Se si aspetta IllegalArgumentException, manca.


5

Alcune raccolte presuppongono che nullvenga rifiutato utilizzando NullPointerExceptionanziché IllegalArgumentException. Ad esempio, se si confronta un set contenente nullun set che rifiuta null, il primo set chiamerà containsAlll'altro e lo catturerà NullPointerException, ma non IllegalArgumentException. (Sto guardando l'implementazione di AbstractSet.equals.)

Si potrebbe ragionevolmente sostenere che l'utilizzo di eccezioni non controllate in questo modo è un antipattern, che il confronto di raccolte che contengono nullraccolte che non possono contenere nullè un probabile bug che dovrebbe davvero produrre un'eccezione o che inserire nulluna raccolta è una cattiva idea . Tuttavia, a meno che tu non sia disposto a dire che equalsdovrebbe generare un'eccezione in tal caso, sei bloccato a ricordare che NullPointerExceptionè necessario in determinate circostanze ma non in altre. ("IAE prima di NPE tranne dopo 'c' ...")


Non vedo come il contenuto generi un NPE a seconda di un elemento all'interno della raccolta. L'unico motivo per cui viene generato un NPE (afaict) è se la raccolta stessa è nulla (nel qual caso viene generato l'NPE perché tenta di accedere al suo iteratore). Ciò solleva tuttavia la questione se l'input null debba essere verificato o se debba propagarsi fino a quando non si tenta di accedere.
Alowaniak,

2
new TreeSet<>().containsAll(Arrays.asList((Object) null));genera NPEperché Listcontiene null.
Chris Povirk,

1
Ah davvero, TreeSet # contiene genera NPE "se l'elemento specificato è nullo e questo set utilizza un ordinamento naturale o il suo comparatore non consente elementi nulli". Ho solo guardato AbstractSet che consente null, il mio male. Personalmente lo trovo strano, ma non solo restituisce false, poiché in quel caso non può essere aggiunto nulla.
Alowaniak,

5

Come domanda soggettiva questa dovrebbe essere chiusa, ma poiché è ancora aperta:

Questo fa parte della politica interna utilizzata nella mia precedente sede di servizio e ha funzionato davvero bene. Tutto questo è a memoria, quindi non ricordo l'esatta formulazione. Vale la pena notare che non hanno utilizzato eccezioni verificate, ma questo va oltre lo scopo della domanda. Le eccezioni incontrollate che hanno usato rientravano in 3 categorie principali.

NullPointerException: non lanciare intenzionalmente. Gli NPE devono essere generati solo dalla VM quando si fa riferimento a un riferimento null. Tutti gli sforzi possibili devono essere fatti per garantire che questi non vengano mai lanciati. @Nullable e @NotNull dovrebbero essere usati insieme agli strumenti di analisi del codice per trovare questi errori.

IllegalArgumentException: generato quando un argomento di una funzione non è conforme alla documentazione pubblica, in modo tale che l'errore possa essere identificato e descritto in termini di argomenti passati. La situazione del PO rientrerebbe in questa categoria.

IllegalStateException: generata quando viene chiamata una funzione e i suoi argomenti sono inattesi al momento in cui vengono passati o incompatibili con lo stato dell'oggetto di cui fa parte il metodo.

Ad esempio, c'erano due versioni interne di IndexOutOfBoundsException utilizzate in cose che avevano una lunghezza. Una sottoclasse di IllegalStateException, utilizzata se l'indice era maggiore della lunghezza. L'altra una sottoclasse di IllegalArgumentException, utilizzata se l'indice era negativo. Questo perché potevi aggiungere più oggetti all'oggetto e l'argomento sarebbe valido, mentre un numero negativo non è mai valido.

Come ho già detto, questo sistema funziona davvero bene e ci è voluto qualcuno per spiegare perché c'è la distinzione: "A seconda del tipo di errore, è abbastanza semplice per te capire cosa fare. Anche se non riesci davvero a capire capire cosa è andato storto è possibile capire dove rilevare quell'errore e creare ulteriori informazioni di debug ".

NullPointerException: gestire il caso Null o inserire un'asserzione in modo che l'NPE non venga lanciato. Se metti un'asserzione è solo uno degli altri due tipi. Se possibile, continua il debug come se l'asserzione fosse presente in primo luogo.

IllegalArgumentException: hai qualcosa di sbagliato nel tuo sito di chiamata. Se i valori passati vengono da un'altra funzione, scopri perché stai ricevendo un valore errato. Se si trasmette uno dei tuoi argomenti propagati, l'errore controlla lo stack di chiamate fino a trovare la funzione che non restituisce ciò che ti aspetti.

IllegalStateException: non hai chiamato le tue funzioni nell'ordine corretto. Se stai usando uno dei tuoi argomenti, controllali e lancia un'eccezione IllegalArgumentException che descrive il problema. Puoi quindi propagare le guance contro lo stack fino a quando non trovi il problema.

Ad ogni modo, il suo punto era che puoi solo copiare IllegalArgumentAssertions nello stack. Non è possibile propagare illegalStateExceptions o NullPointerExceptions nello stack perché avevano qualcosa a che fare con la tua funzione.


4

In generale, uno sviluppatore non dovrebbe mai lanciare una NullPointerException. Questa eccezione viene generata dal runtime quando il codice tenta di dereferenziare una variabile il cui valore è nullo. Pertanto, se il tuo metodo vuole esplicitamente vietare null, invece di avere un valore null che genera un valore NullPointerException, dovresti lanciare un IllegalArgumentException.


9
JavaDoc su NPE ha un'altra opinione: "Le applicazioni dovrebbero lanciare istanze di questa classe per indicare altri usi illegali dell'oggetto null.". Non essere così categorico
Donz,

4

Volevo individuare argomenti Null da altri argomenti illegali, quindi ho derivato un'eccezione da IAE denominata NullArgumentException. Senza nemmeno dover leggere il messaggio di eccezione, so che un argomento nullo è stato passato in un metodo e leggendo il messaggio, scopro quale argomento è nullo. Prendo ancora NullArgumentException con un gestore IAE, ma nei miei registri è dove posso vedere rapidamente la differenza.


Ho adottato l'approccio "lancio nuovo IllegalArgumentException (" foo == null ")". Devi comunque registrare il nome della variabile (per essere certo che stai osservando la giusta dichiarazione ecc.)
Thorbjørn Ravn Andersen,

4

la dicotomia ... Non si sovrappongono? Solo le parti non sovrapposte di un intero possono creare una dicotomia. Per come la vedo:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

1
Ciò raddoppierebbe le spese generali per la creazione di eccezioni e non sarebbe di grande aiuto in quanto la cattura NullPointerExceptionnon farebbe nulla. L'unica cosa che potrebbe aiutare è IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, ma non abbiamo eredità multipla.
maaartinus,

Ritengo che eccezioni più specifiche dovrebbero essere racchiuse in eccezioni più generali. NPE è per un'espressione mentre IAE è per un metodo. Poiché i metodi contengono istruzioni che contengono espressioni, IAE è più generale.
Sgene9,

Per quanto riguarda le spese generali, non ne ho idea. Ma dal momento che gli stack stack sarebbero sostanzialmente identici, tranne per il fatto che il nome dell'eccezione è cambiato nel mezzo, penso che non ci dovrebbero essere troppi costi generali per le doppie eccezioni. Se uno è preoccupato per il sovraccarico, può usare le istruzioni "if" per restituire un valore nullo o -1 invece di generare un'eccezione.
Sgene9,

4

NullPointerExceptiongenerato quando si tenta di accedere a un oggetto con una variabile di riferimento il cui valore corrente è null.

IllegalArgumentException generato quando un metodo riceve un argomento formattato in modo diverso da quello previsto dal metodo.


3

Secondo il tuo scenario, IllegalArgumentExceptionè la scelta migliore, perché nullnon è un valore valido per la tua proprietà.


0

Idealmente, non dovrebbero essere generate eccezioni di runtime. Un'eccezione selezionata (eccezione aziendale) deve essere creata per il tuo scenario. Perché se una di queste eccezioni viene generata e registrata, guida in modo errato lo sviluppatore durante l'esecuzione dei registri. Invece le eccezioni aziendali non creano quel panico e di solito vengono ignorate durante la risoluzione dei problemi dei registri.


-1

Le definizioni dai collegamenti alle due eccezioni sopra riportate sono IllegalArgumentException: generata per indicare che un metodo ha superato un argomento illegale o inappropriato. NullPointerException: generata quando un'applicazione tenta di utilizzare null nel caso in cui sia richiesto un oggetto.

La grande differenza qui è che IllegalArgumentException dovrebbe essere usato quando si controlla che un argomento di un metodo sia valido. NullPointerException dovrebbe essere usato ogni volta che un oggetto viene "usato" quando è nullo.

Spero che questo aiuti a mettere i due in prospettiva.


1
Il bit saliente è che è l' applicazione che utilizza null, non il runtime. Quindi esiste una sovrapposizione piuttosto ampia tra "quando un metodo è stato passato un argomento illegale o inappropriato" e "quando un'applicazione utilizza null". In teoria, se un'app passa un null per un campo che richiede non null, entrambi i criteri vengono soddisfatti.
Christopher Smith,

-1

Se si tratta di un "setter", o da qualche parte sto per usare un membro in seguito, tendo a usare IllegalArgumentException.

Se è qualcosa che userò (dereference) in questo momento nel metodo, lancio proattivamente una NullPointerException. Mi piace di più che lasciare che il runtime lo faccia, perché posso fornire un messaggio utile (sembra che anche il runtime possa fare questo, ma è un rant per un altro giorno).

Se eseguo l'override di un metodo, utilizzo qualunque sia il metodo utilizzato.


-1

Dovresti lanciare un'eccezione IllegalArgumentException, poiché renderà ovvio al programmatore che ha fatto qualcosa di non valido. Gli sviluppatori sono così abituati a vedere l'NPE lanciato dalla VM, che qualsiasi programmatore non si accorgerebbe immediatamente del suo errore e inizierebbe a guardarsi attorno in modo casuale, o peggio, incolpando il codice di essere "difettoso".


4
Ci dispiace, se un programmatore si guarda intorno "in modo casuale" dopo aver ottenuto qualsiasi tipo di eccezione ... la modifica del nome di un'eccezione non è di grande aiuto.
Christopher Smith,

-1

In questo caso, IllegalArgumentException trasmette all'utente informazioni chiare utilizzando l'API secondo cui "non deve essere nullo". Come altri utenti del forum hanno sottolineato, è possibile utilizzare NPE se si desidera purché si trasmettano le informazioni giuste all'utente utilizzando l'API.

GaryF e tweakt hanno lasciato cadere riferimenti "Effective Java" (che giuro) che raccomanda l'uso di NPE. E guardare come sono costruite altre buone API è il modo migliore per vedere come costruire la tua API.

Un altro buon esempio è quello di guardare le API di primavera. Ad esempio, org.springframework.beans.BeanUtils.instantiateClass (costruttore costruttore, Object [] args) ha una riga Assert.notNull (ctor, "Il costruttore non deve essere nullo"). Il metodo org.springframework.util.Assert.notNull (oggetto oggetto, messaggio stringa) verifica se l'argomento (oggetto) passato è nullo e in caso affermativo genera un nuovo IllegalArgumentException (messaggio) che viene quindi catturato nell'organizzazione. Metodo springframework.beans.BeanUtils.instantiateClass (...).


-5

Se scegli di lanciare un NPE e stai usando l'argomento nel tuo metodo, potrebbe essere ridondante e costoso controllare esplicitamente un valore nullo. Penso che la VM lo faccia già per te.


Il tempo di esecuzione non includerà un messaggio significativo.
mP.

In realtà questo commento potrebbe derivare qualche altra opinione. Lascia parlare la VM, NPEma i programmatori parlano IAEprima della VM, se lo desiderano.
Jin Kwon,

1
Costoso? Non credo che == null sia così costoso ... Inoltre, l'argomento null può essere semplicemente archiviato per un uso successivo e genererà un'eccezione molto dopo la chiamata del metodo, rendendo più difficile tenere traccia dell'errore. Oppure puoi creare un oggetto costoso prima di usare l'argomento null e così via. La rilevazione precoce sembra essere una buona opzione.
PhiLho,

il voto negativo di questa risposta è incomprensione dell'hardware che sta dietro. Certamente i controlli hardware (che fa la CPU) sono più economici di quel controllo esplicito. La dereferenziazione di null è un caso speciale SegmentationFault (SegV) (accesso a una pagina non di proprietà del processo) che CPU / OS controlla e JRE gestisce come un caso speciale che genera NullPointerException.
digital_infinity
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.