DISABILITARE ADBLOCK

ADBlock sta bloccando alcuni contenuti del sito

ADBlock errore
risultati trovati: 

DOMANDA

Ho un metodo setter semplice per una proprietà e null non è appropriato per questa particolare proprietà. Sono sempre stato strappato in questa situazione: dovrei lanciare un IllegalArgumentException o 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?

SOLUZIONE

Sembra che sia richiesto un IllegalArgumentException se non si desidera che null sia un valore consentito e NullPointerException sarebbe generato se si sta tentando di utilizzare una variabile che risulta essere null .

Se ti va lasciaci una tua opinione

L'articolo ti è stato utile ed è tradotto correttamente?

ALTRI SUGGERIMENTI

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

Innanzitutto, NPE JavaDoc elenca esplicitamente i casi in cui NPE è appropriato. Si noti che tutti vengono lanciati dal runtime quando null viene utilizzato in modo inappropriato. Al contrario, il IAE JavaDoc non ha potuto per essere più chiari: "lanciato per indicare che un metodo è stato approvato un argomento illegale o inappropriato." Sì, sei tu!

Secondo, quando vedi un NPE in una traccia dello stack, cosa pensi? Probabilmente qualcuno ha indicato un null . Quando vedi IAE, supponi che il chiamante del metodo nella parte superiore dello stack abbia passato un valore illegale. Ancora una volta, la seconda 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 comportamenti diversi: 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 dei parametri errati saranno IAE, quindi perché non essere coerenti? Perché un null illegale è 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.

Lo standard è lanciare NullPointerException . "Java efficace" 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, tutti i metodi errati   le invocazioni si riducono a un illegale   argomento o stato illegale, ma altro   le eccezioni sono normalmente utilizzate per   alcuni tipi di argomenti illegali e   stati. Se un chiamante passa null   alcuni parametri per i quali valori nulli   sono vietati, la convenzione impone   che NullPointerException deve essere lanciato   anziché IllegalArgumentException. "

Ero completamente favorevole a lanciare IllegalArgumentException per parametri null, fino ad oggi, quando ho notato il metodo java.util.Objects.requireNonNull in Java 7. Con quello metodo, invece di fare:

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

puoi fare:

Objects.requireNonNull(param);

e genererà un NullPointerException se il parametro che passi è null .

Dato che quel metodo è quello giusto nel mezzo di java.util ritengo che la sua esistenza sia un'indicazione abbastanza forte che lanciare NullPointerException sia " il modo Java di fare cose " ;.

Penso di essere deciso in ogni caso.

Nota che gli argomenti sul debug hard sono falsi perché puoi ovviamente fornire un messaggio a NullPointerException dicendo cosa era null e perché non dovrebbe essere null. Proprio come con IllegalArgumentException .

Un ulteriore vantaggio di NullPointerException è che, in un codice critico ad alte prestazioni, è possibile rinunciare a un controllo esplicito per null (e un NullPointerException con un messaggio di errore intuitivo) e fai semplicemente affidamento sul NullPointerException che otterrai automaticamente quando chiami un metodo sul parametro null. A condizione che tu chiami un metodo rapidamente (cioè fallisci velocemente), allora hai essenzialmente lo stesso effetto, non proprio 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 null, ma è bello avere la possibilità di cambiarlo se le prestazioni dettano senza rompere il contratto pubblicato del metodo / costruttore.

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 generano proattivamente NullPointerException .

Ad esempio, Javadoc per Map.containsKey indica:

  

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

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

Il modello va:

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

Qualunque cosa tu faccia, non consentire l'impostazione di un valore errato e generare un'eccezione in un secondo momento quando un altro codice tenta di utilizzarlo. Questo rende il debug un incubo. Dovresti sempre seguire le istruzioni " fail-fast " linea di principio.

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

  • Il 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 segnalato in modo inappropriato rispetto al fatto che un metodo abbia rilevato un null inappropriato e generato un'eccezione disattivata.

  • 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 , una varietà di eccezioni di errore di sintassi, IndexOutOfBoundsException , errori di autenticazione, ecc., ecc.

In generale, ritengo che NPE sia molto diffamato perché tradizionalmente è stato associato a codice che non riesce a seguire principio del fallimento veloce . 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ù sei preciso con il nome, più chiarezza dai al chiamante.

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

Se è un metodo setter e null gli viene passato, penso che avrebbe più senso lanciare un IllegalArgumentException . Un NullPointerException sembra avere più senso nel caso in cui si stia tentando di utilizzare effettivamente il null .

Quindi, se lo stai usando ed è null , NullPointer . Se viene passato ed è null , IllegalArgument .

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 sento che lanciare qualcosa come una NullArgumentException o IllegalArgumentException descrive più accuratamente le circostanze eccezionali, io e i miei colleghi abbiamo scelto di rinviare il consiglio di Bloch sull'argomento.

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'uso di un NPE poiché mi sta dicendo che il problema era con un argomento che ho passato al metodo e non con un valore che potrebbe essere stato generato durante l'esecuzione del metodo.

I miei 2 centesimi

La pratica accettata se usare IllegalArgumentException (messaggio String) per dichiarare un parametro non valido e fornire quanti più dettagli possibile ... Quindi per dire che un parametro è stato trovato nullo mentre l'eccezione non è nulla, faresti qualcosa del genere:

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

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

In realtà, la questione del lancio di 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 degli argomenti devono essere indicate il più rapidamente possibile (- > fast fail), 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, genera NegativeArraySizeException
  • in caso di un argomento illegale che 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!

Esistono 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 violazioni del vincolo dell'argomento comportino IllegalArgumentException, poiché la maggior parte 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 nullo 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) Il mapping 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 (ad esempio un bug) in un'eccezione IllegalArgumentException della tua API. Anche la mappatura più attenta rischia quindi di mascherare gli errori di programmazione di altri produttori di biblioteche come violazioni dei vincoli degli argomenti degli utenti del tuo metodo, che è semplicemente un comportamento collinare!

Con la pratica standard, d'altra parte, le regole rimangono semplici e le cause di eccezione rimangono non mascherate e specifiche. Per il metodo chiamante, anche le regole sono semplici: - se riscontri un'eccezione di runtime documentata di qualsiasi tipo perché hai passato un valore illegale, ripeti la chiamata con un valore predefinito (poiché queste specifiche eccezioni sono necessarie) oppure correggi 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.

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 in modo esplicito non consentire null, al contrario di avere un valore null che genera un valore NullPointerException, dovresti generare un IllegalArgumentException.

Il lancio di un'eccezione esclusiva degli argomenti null (sia NullPointerException o un tipo personalizzato) rende i test automatizzati null più affidabili. Questo test automatizzato può essere eseguito con la riflessione e una serie di valori predefiniti, come in Guava 's NullPointerTester . Ad esempio, NullPointerTester tenterebbe 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: " " ;, null e null, ImmutableList.of () . Verificherebbe che ognuna di queste chiamate genera il NullPointerException previsto. Per questa implementazione, passare un elenco null non non produce NullPointerException . Tuttavia, produce un IllegalArgumentException perché NullPointerTester utilizza una stringa predefinita di " " . Se NullPointerTester prevede solo NullPointerException per i valori null , rileva il bug. Se si aspetta IllegalArgumentException , lo manca.

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 utilizzato 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 usate 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 detto, questo sistema funziona davvero bene e qualcuno ha spiegato perché c'è la differenza: " A seconda del tipo di errore, è abbastanza semplice per te capire cosa fare. Anche se non riesci davvero a capire cosa è andato storto, puoi capire dove rilevare quell'errore e creare ulteriori informazioni di debug. & Quot;

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 passi 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 c'è modo per te di propagare illegalStateExceptions o NullPointerExceptions nello stack perché avevano qualcosa a che fare con la tua funzione.

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 è stato passato un argomento null in un metodo e leggendo il messaggio, scopro quale argomento è null. Prendo ancora NullArgumentException con un gestore IAE, ma nei miei registri è dove posso vedere rapidamente la differenza.

la dicotomia ... Non si sovrappongono? Solo le parti non sovrapposte di un intero possono creare una dicotomia. A mio modo di vedere:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

Alcune raccolte presuppongono che null sia rifiutato utilizzando NullPointerException anziché IllegalArgumentException . Ad esempio, se si confronta un set contenente null con un set che rifiuta null , il primo set chiamerà IncludesAll sull'altro e ne prenderà 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 tra raccolte che contengono null con raccolte che non possono contenere null è probabilmente un bug che davvero dovrebbe produrre un'eccezione o che mettere null in una raccolta non è affatto una buona idea. Tuttavia, a meno che tu non sia disposto a dire che uguale a dovrebbe generare un'eccezione in tal caso, sei bloccato a ricordare che NullPointerException è richiesto in determinate circostanze ma non in altre . (" IAE prima di NPE tranne dopo 'c' ... ")

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

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

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

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.

Le definizioni dai collegamenti alle due eccezioni sopra sono IllegalArgumentException: generato 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 è null.

Spero che questo aiuti a mettere i due in prospettiva.

Se si tratta di un "setter" o di un punto in cui un membro verrà utilizzato in seguito, tendo a utilizzare IllegalArgumentException.

Se è qualcosa che userò ora (dereference) 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 farlo, ma è un rant per un altro giorno).

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

Dovresti lanciare un 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".

In questo caso, IllegalArgumentException trasmette all'utente informazioni chiare usando la tua API che " non dovrebbe 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 " Efficace Java " (che giuro) riferimenti che raccomandano 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 Spring. Ad esempio, org.springframework.beans.BeanUtils.instantiateClass (Costruttore ctor, Object [] args) ha una riga Assert.notNull (ctor, " Costruttore non deve essere null "). Il metodo org.springframework.util.Assert.notNull (oggetto oggetto, messaggio stringa) verifica se l'argomento (oggetto) passato è nullo e, se lo è, genera un nuovo IllegalArgumentException (messaggio) che viene quindi catturato nell'organizzazione. Metodo springframework.beans.BeanUtils.instantiateClass (...).

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow