Quando utilizzare un'asserzione e quando utilizzare un'eccezione


121

La maggior parte delle volte userò un'eccezione per verificare una condizione nel mio codice, mi chiedo quando è il momento opportuno per utilizzare un'asserzione?

Per esempio,

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

Potrebbe indicare come si inserisce qui un'affermazione? Devo usare un'affermazione?

Sembra che non utilizzo mai asserzioni nel codice di produzione e vedo solo asserzioni negli unit test. So che nella maggior parte dei casi posso semplicemente usare l'eccezione per eseguire il controllo come sopra, ma voglio conoscere il modo appropriato per farlo "professionalmente".

Risposte:


81

Le asserzioni dovrebbero essere utilizzate per verificare qualcosa che non dovrebbe mai accadere, mentre un'eccezione dovrebbe essere utilizzata per verificare qualcosa che potrebbe accadere.

Ad esempio, una funzione potrebbe dividere per 0, quindi dovrebbe essere utilizzata un'eccezione, ma un'asserzione potrebbe essere utilizzata per verificare che l'hard disk scompaia improvvisamente.

Un'asserzione interromperà l'esecuzione del programma, ma un'eccezione consentirebbe al programma di continuare l'esecuzione.

Nota che if(group != null)non è un'affermazione, è solo un condizionale.


3
"un'asserzione potrebbe essere utilizzata per verificare che l'hard disk scompaia improvvisamente" - Direi che non è corretto: perché vorresti che fosse gestito durante lo sviluppo, ma non in produzione (quando le asserzioni sono tipicamente disabilitate)?
Herman

71
Il commento sul disco rigido è sbagliato. Le asserzioni servono per verificare la presenza di errori nella logica del codice. Mai e poi mai usarli per controllare qualcosa che non controlli. Ricorda, se un'asserzione fallisce significa che il tuo codice è sbagliato .
Ian Goldby

1
@Mario Il tuo condizionale potrebbe essere sostituito con un'affermazione come questa: assert group! = Null
IgorGanapolsky

1
Downvoted perché l'esempio del disco rigido contraddice la tua filosofia. I dischi rigidi "scomparendo" (dal punto di vista del codice) potrebbero effettivamente accadere nella realtà, non importa quanto improbabile. Come dice @IanGoldby, le asserzioni dovrebbero dipendere esclusivamente da cose controllate dal tuo codice.
Vicky Chijwani

Una risposta molto migliore se pubblicata da Gregory Pakosz, per favore leggi quel post.
ormurin

169

Fuori di testa (l'elenco potrebbe essere incompleto ed è troppo lungo per essere contenuto in un commento), direi:

  • utilizzare le eccezioni durante il controllo dei parametri passati a metodi e costruttori pubblici o protetti
  • utilizzare le eccezioni quando si interagisce con l'utente o quando si prevede che il codice client si riprenda da una situazione eccezionale
  • utilizzare le eccezioni per risolvere i problemi che potrebbero verificarsi
  • utilizzare le asserzioni durante il controllo delle pre-condizioni, delle post-condizioni e delle invarianti del codice privato / interno
  • utilizza le asserzioni per fornire feedback a te stesso o al tuo team di sviluppatori
  • usa le asserzioni quando controlli cose che è molto improbabile che accadano altrimenti significa che c'è un grave difetto nella tua applicazione
  • usa le affermazioni per affermare cose che (presumibilmente) sai essere vere

In altre parole, le eccezioni riguardano la robustezza dell'applicazione mentre le asserzioni ne riguardano la correttezza.

Le asserzioni sono progettate per essere economiche da scrivere, puoi usarle quasi ovunque e sto usando questa regola pratica: più un'asserzione sembra stupida, più è preziosa e più informazioni contiene. Quando si esegue il debug di un programma che non si comporta nel modo giusto, si verificheranno sicuramente le possibilità di errore più ovvie in base alla propria esperienza. Quindi verificherai problemi che semplicemente non possono accadere: questo è esattamente quando le affermazioni aiutano molto e fanno risparmiare tempo.


53
Mi piace il modo in cui hai formulato questo: le eccezioni affrontano la robustezza della tua applicazione mentre le asserzioni riguardano la sua correttezza .
M. Dudley


E se ti capita di cercare una libreria di asserzione personalizzata C ++, ho rilasciato github.com/gpakosz/Assert
Gregory Pakosz

26

Ricorda che le asserzioni possono essere disabilitate in fase di esecuzione utilizzando i parametri e sono disabilitate per impostazione predefinita , quindi non contare su di esse tranne che per scopi di debug.

Inoltre dovresti leggere l' articolo Oracle su assert per vedere più casi in cui usare - o non usare - assert.


Tonalità tonalità tonalità Mi chiedevo perché il mio codice non funzionasse in Eclipse ma funzionasse correttamente sulla riga di comando.
Steve

15

Come regola generale:

  • Usa le asserzioni per i controlli di coerenza interni dove non importa affatto se qualcuno le disattiva. (Notare che il javacomando disattiva tutte le asserzioni per impostazione predefinita.)
  • Usa test regolari per qualsiasi tipo di controllo che cosa non dovrebbe essere disattivato. Ciò include controlli difensivi che proteggono da potenziali danni causati da bug e qualsiasi dato / richiesta di convalida / qualsiasi cosa fornita dagli utenti o servizi esterni.

Il codice seguente dalla tua domanda è di cattivo stile e potenzialmente difettoso

try {
    group = service().getGroup("abc");
} catch (Exception e) {
    //i dont log error because i know whenever error occur mean group not found
}

Il problema è che NON sai che un'eccezione significa che il gruppo non è stato trovato. È anche possibile che la service()chiamata abbia nullgenerato un'eccezione o che sia stata restituita causando un errore NullPointerException.

Quando si rileva un'eccezione "prevista", è necessario rilevare solo l'eccezione prevista . Catturando java.lang.Exception(e soprattutto non registrandolo), si rende più difficile diagnosticare / eseguire il debug del problema e potenzialmente consentire all'app di fare più danni.


4

Bene, in Microsoft, la raccomandazione era di lanciare eccezioni in tutte le API che rendi disponibili pubblicamente e di utilizzare Asserts in tutti i tipi di presupposti che fai sul codice interno. È una definizione un po 'approssimativa, ma immagino che spetti a ogni sviluppatore tracciare la linea.

Per quanto riguarda l'uso delle eccezioni, come dice il nome, il loro utilizzo dovrebbe essere eccezionale, quindi per il codice che presenti sopra, la getGroupchiamata dovrebbe tornare nullse non esiste alcun servizio. L'eccezione dovrebbe verificarsi solo se un collegamento di rete si interrompe o qualcosa del genere.

Immagino che la conclusione sia che spetta al team di sviluppo definire i confini tra asserzione e eccezioni per ciascuna applicazione.


IMHO, il problema con questo tipo di raccomandazione è che va bene finché il confine tra le parti pubbliche e private di un'API è abbastanza fisso. Se stai sviluppando un nuovo codice, quel confine è spesso piuttosto fluido ...
Len Holgate

Sì hai ragione. È una linea guida ma alla fine della giornata è lasciata alla sensibilità dei programmatori. Non penso che ci sia una linea di definizione definitiva per questi quindi immagino che tu vada con quello che pensi sia giusto leggendo un sacco di codice diverso.
rui

3

Secondo questo documento http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general , "L'istruzione assert è appropriata per precondizione non pubblica, postcondizione e invariante di classe controllo. Il controllo delle precondizioni pubbliche dovrebbe comunque essere eseguito da controlli all'interno di metodi che risultino in eccezioni particolari e documentate, come IllegalArgumentException e IllegalStateException. "

Se vuoi saperne di più su precondizione, postcondizione e invariante di classe, controlla questo documento: http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions . Contiene anche esempi di utilizzo di asserzioni.


1

Il test per null rileverà solo i null che causano problemi, mentre un try / catch come lo hai catturerà qualsiasi errore.

In generale, try / catch è più sicuro, ma leggermente più lento e devi stare attento a catturare tutti i tipi di errore che possono verificarsi. Quindi direi di usare try / catch: un giorno il codice getGroup potrebbe cambiare e potresti aver bisogno di quella rete più grande.


1

È possibile utilizzare questa semplice differenza in mente durante il loro utilizzo. Le eccezioni verranno utilizzate per controllare gli errori previsti e imprevisti chiamati errori verificati e deselezionati mentre l'asserzione viene utilizzata principalmente per scopi di debug in fase di esecuzione per vedere se le ipotesi sono convalidate o meno.


1

Confesso di essere un po 'confuso dalla tua domanda. Quando una condizione di asserzione non viene soddisfatta, viene generata un'eccezione. In modo confuso, questo è chiamato AssertionError . Nota che è deselezionato, come (ad esempio) IllegalArgumentException che viene lanciata in circostanze molto simili.

Quindi usando le asserzioni in Java

  1. è un mezzo più conciso per scrivere un blocco condizione / lancio
  2. consente di attivare / disattivare questi controlli tramite i parametri JVM. Normalmente lascerei sempre attivi questi controlli, a meno che non influiscano sulle prestazioni di runtime o abbiano una penalità simile.

AssertionError è una sottoclasse di Error non RuntimeException.
Stephen C

Ah. Ovviamente. Stavo pensando di selezionare / deselezionare. Ora corretto
Brian Agnew

Spiega cosa sono le affermazioni (da un punto di vista controverso), ma non quando usarle esattamente.
Karl Richter

1

Vedere la sezione 6.1.2 (Asserzioni e altro codice di errore) della documentazione di Sun al seguente collegamento.

http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

Questo documento fornisce i migliori consigli che ho visto su quando utilizzare le asserzioni. Citando dal documento:

"Una buona regola pratica è che dovresti usare un'affermazione per casi eccezionali di cui vorresti dimenticare. Un'asserzione è il modo più rapido per affrontare e dimenticare una condizione o uno stato che non ti aspetti di dover avere a che fare con."


0

Purtroppo le asserzioni possono essere disabilitate. Quando sei in produzione hai bisogno di tutto l'aiuto che puoi ottenere per rintracciare qualcosa di imprevisto, quindi afferma che si squalifica.

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.