Quali sono alcuni esempi di vita reale per comprendere il ruolo chiave delle asserzioni?
Quali sono alcuni esempi di vita reale per comprendere il ruolo chiave delle asserzioni?
Risposte:
Le asserzioni (tramite la parola chiave assert ) sono state aggiunte in Java 1.4. Sono utilizzati per verificare la correttezza di un invariante nel codice. Non devono mai essere attivati nel codice di produzione e sono indicativi di un bug o di un uso improprio di un percorso del codice. Possono essere attivati in fase di esecuzione tramite l' -ea
opzione sul java
comando, ma non sono attivati per impostazione predefinita.
Un esempio:
public Foo acquireFoo(int id) {
Foo result = null;
if (id > 50) {
result = fooService.read(id);
} else {
result = new Foo(id);
}
assert result != null;
return result;
}
assert
per controllare i parametri del metodo pubblico ( docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html ). Questo dovrebbe lanciare Exception
invece di uccidere il programma.
This convention is unaffected by the addition of the assert construct. Do not use assertions to check the parameters of a public method. An assert is inappropriate because the method guarantees that it will always enforce the argument checks. It must check its arguments whether or not assertions are enabled. Further, the assert construct does not throw an exception of the specified type. It can throw only an AssertionError.
docs.oracle.com/javase/8/docs/technotes/guides/language/...
Supponiamo che tu debba scrivere un programma per controllare una centrale nucleare. È abbastanza ovvio che anche l'errore più piccolo potrebbe avere risultati catastrofici, quindi il tuo codice deve essere privo di bug (supponendo che JVM sia privo di bug per il bene dell'argomento).
Java non è un linguaggio verificabile, il che significa che non è possibile calcolare che il risultato dell'operazione sarà perfetto. Il motivo principale di ciò sono i puntatori: possono puntare ovunque o in nessun luogo, quindi non possono essere calcolati per avere questo valore esatto, almeno non entro un ragionevole intervallo di codice. Dato questo problema, non c'è modo di provare che il tuo codice sia nel complesso corretto. Ma quello che puoi fare è dimostrare che almeno trovi ogni bug quando succede.
Questa idea si basa sul paradigma Design-by-Contract (DbC): per prima cosa definisci (con precisione matematica) ciò che il tuo metodo dovrebbe fare, e poi lo verifichi testandolo durante l'esecuzione effettiva. Esempio:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
return a + b;
}
Mentre questo è abbastanza ovvio per funzionare bene, la maggior parte dei programmatori non vedrà il bug nascosto all'interno di questo (suggerimento: Ariane V si è schiantato a causa di un bug simile). Ora DbC definisce che è sempre necessario controllare l'input e l'output di una funzione per verificarne il corretto funzionamento. Java può farlo attraverso affermazioni:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
assert (Integer.MAX_VALUE - a >= b) : "Value of " + a + " + " + b + " is too large to add.";
final int result = a + b;
assert (result - a == b) : "Sum of " + a + " + " + b + " returned wrong sum " + result;
return result;
}
Se questa funzione ora non dovesse funzionare, la noterai. Saprai che c'è un problema nel tuo codice, sai dove si trova e sai cosa lo ha causato (simile a Eccezioni). E ciò che è ancora più importante: smetti di eseguire correttamente quando succede per impedire a qualsiasi altro codice di lavorare con valori errati e potenzialmente causare danni a qualsiasi cosa controlli.
Le eccezioni Java sono un concetto simile, ma non riescono a verificare tutto. Se desideri ancora più controlli (a scapito della velocità di esecuzione) devi utilizzare le asserzioni. In questo modo si gonfia il codice, ma alla fine è possibile consegnare un prodotto in un tempo di sviluppo sorprendentemente breve (prima si corregge un bug, minore è il costo). E inoltre: se c'è qualche bug nel tuo codice, lo rileverai. Non è possibile che un bug scivoli e causi problemi in seguito.
Questo non è ancora una garanzia per il codice privo di bug, ma è molto più vicino a questo, rispetto ai normali programmi.
new IllegalArgumentException
messaggio? Voglio dire, oltre ad avere o aggiungere throws
alla dichiarazione del metodo e al codice per gestire quell'eccezione da qualche altra parte. Perché assert
insetad di lanciare una nuova eccezione? O perché non un if
invece di assert
? Non riesco davvero a ottenere questo :(
a
può essere negativa. La seconda affermazione è inutile; per i valori int, è sempre il caso che a + b - b == a. Quel test può fallire solo se il computer è sostanzialmente rotto. Per difendersi da tale imprevisto, è necessario verificare la coerenza tra più CPU.
Le asserzioni sono uno strumento in fase di sviluppo per rilevare i bug nel codice. Sono progettati per essere facilmente rimossi, quindi non esistono nel codice di produzione. Quindi le asserzioni non fanno parte della "soluzione" che offri al cliente. Sono controlli interni per assicurarsi che le ipotesi che stai facendo siano corrette. L'esempio più comune è testare null. Molti metodi sono scritti in questo modo:
void doSomething(Widget widget) {
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
Molto spesso in un metodo come questo, semplicemente il widget non dovrebbe mai essere nullo. Quindi, se è nullo, c'è un bug nel tuo codice da qualche parte che devi rintracciare. Ma il codice sopra non ti dirà mai questo. Quindi, nel tentativo ben intenzionato di scrivere un codice "sicuro", nascondi anche un bug. È molto meglio scrivere codice in questo modo:
/**
* @param Widget widget Should never be null
*/
void doSomething(Widget widget) {
assert widget != null;
widget.someMethod(); // ...
... // do more stuff with this widget
}
In questo modo, sarai sicuro di catturare questo bug in anticipo. (È anche utile specificare nel contratto che questo parametro non deve mai essere nullo.) Accertarsi di attivare le asserzioni quando si verifica il codice durante lo sviluppo. (E persuadere i tuoi colleghi a farlo anche questo è spesso difficile, che trovo molto fastidioso.)
Ora, alcuni dei tuoi colleghi si opporranno a questo codice, sostenendo che dovresti comunque effettuare il controllo null per evitare un'eccezione nella produzione. In tal caso, l'affermazione è ancora utile. Puoi scriverlo in questo modo:
void doSomething(Widget widget) {
assert widget != null;
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
In questo modo, i tuoi colleghi saranno felici che il controllo null sia disponibile per il codice di produzione, ma durante lo sviluppo, non stai più nascondendo il bug quando il widget è null.
Ecco un esempio del mondo reale: una volta ho scritto un metodo che confrontava due valori arbitrari per l'uguaglianza, in cui entrambi i valori potevano essere nulli:
/**
* Compare two values using equals(), after checking for null.
* @param thisValue (may be null)
* @param otherValue (may be null)
* @return True if they are both null or if equals() returns true
*/
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = thisValue.equals(otherValue);
}
return result;
}
Questo codice delega il lavoro del equals()
metodo nel caso in cui thisValue non sia nullo. Ma assume ilequals()
metodo soddisfi correttamente il contratto equals()
gestendo correttamente un parametro null.
Un collega ha obiettato al mio codice, dicendomi che molte delle nostre classi hanno equals()
metodi errati che non testano per null, quindi dovrei mettere quel controllo in questo metodo. È discutibile se questo è saggio, o se dovremmo forzare l'errore, quindi possiamo individuarlo e risolverlo, ma ho rinviato al mio collega e messo un controllo nullo, che ho contrassegnato con un commento:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = otherValue != null && thisValue.equals(otherValue); // questionable null check
}
return result;
}
Il controllo aggiuntivo qui, other != null
è necessario solo se il equals()
metodo non riesce a verificare la null come richiesto dal suo contratto.
Piuttosto che impegnarmi in un fruttuoso dibattito con il mio collega sulla saggezza di lasciare che il codice errato rimanga nella nostra base di codice, ho semplicemente inserito due affermazioni nel codice. Queste affermazioni mi faranno sapere, durante la fase di sviluppo, se una delle nostre classi non riesce a implementarsi equals()
correttamente, quindi posso risolverlo:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
assert otherValue == null || otherValue.equals(null) == false;
} else {
result = otherValue != null && thisValue.equals(otherValue);
assert thisValue.equals(null) == false;
}
return result;
}
I punti importanti da tenere a mente sono questi:
Le asserzioni sono solo strumenti in fase di sviluppo.
Il punto di un'affermazione è farti sapere se c'è un bug, non solo nel tuo codice, ma nella tua base di codice . (Le asserzioni qui in realtà contrassegneranno i bug in altre classi.)
Anche se il mio collega fosse sicuro che le nostre lezioni fossero state scritte correttamente, le affermazioni qui sarebbero comunque utili. Verranno aggiunte nuove classi che potrebbero non essere verificate per null e questo metodo può contrassegnare tali bug per noi.
Nello sviluppo, dovresti sempre attivare le asserzioni, anche se il codice che hai scritto non usa asserzioni. Il mio IDE è impostato per farlo sempre per impostazione predefinita per qualsiasi nuovo eseguibile.
Le asserzioni non cambiano il comportamento del codice in produzione, quindi il mio collega è contento che il controllo null sia presente e che questo metodo verrà eseguito correttamente anche se il equals()
metodo è difettoso. Sono felice perché prenderò qualsiasi equals()
metodo con errori durante lo sviluppo.
Inoltre, dovresti testare la tua politica di asserzione inserendo un'asserzione temporanea che fallirà, quindi puoi essere certo di essere avvisato, sia attraverso il file di registro o una traccia dello stack nel flusso di output.
Molte buone risposte spiegano cosa fa la assert
parola chiave, ma pochi rispondono alla vera domanda "quando dovrebbeassert
essere usata parola chiave nella vita reale?"
La risposta: quasi mai .
Le asserzioni, come concetto, sono meravigliose. Il buon codice ha molte if (...) throw ...
affermazioni (e ai loro parenti piace Objects.requireNonNull
e Math.addExact
). Tuttavia, alcune decisioni di progettazione hanno notevolmente limitato l'utilità della assert
parola chiave stessa.
L'idea alla base della assert
parola chiave è l'ottimizzazione prematura e la caratteristica principale è quella di poter facilmente disattivare tutti i controlli. In effetti, ilassert
controlli sono disattivati per impostazione predefinita.
Tuttavia, è di fondamentale importanza che i controlli invarianti continuino a essere effettuati in produzione. Questo perché una perfetta copertura dei test è impossibile e tutto il codice di produzione avrà bug che le asserzioni dovrebbero aiutare a diagnosticare e mitigare.
Pertanto, l'uso di if (...) throw ...
dovrebbe essere preferito, così come è richiesto per il controllo dei valori dei parametri dei metodi pubblici e per il lancio IllegalArgumentException
.
Occasionalmente, si potrebbe essere tentati di scrivere un controllo invariante che richiede un tempo indesiderabilmente lungo per l'elaborazione (e viene chiamato abbastanza spesso perché contenga). Tuttavia, tali controlli rallenteranno i test, il che è anche indesiderabile. Tali controlli che richiedono molto tempo sono generalmente scritti come test unitari. Tuttavia, a volte può avere senso utilizzare assert
per questo motivo.
Non usare assert
semplicemente perché è più pulito e più bello di if (...) throw ...
(e lo dico con grande dolore, perché mi piace pulito e carino). Se semplicemente non puoi aiutarti e puoi controllare come viene avviata la tua applicazione, sentiti libero di usare assert
ma abilita sempre le asserzioni in produzione. Certo, questo è quello che tendo a fare. Sto spingendo per un'annotazione lombok che farà comportare assert
di più if (...) throw ...
. Vota qui.
(Rant: gli sviluppatori JVM erano un sacco di programmatori terribili e prematuramente ottimizzati. Ecco perché si sentono così tanti problemi di sicurezza nel plugin Java e JVM. Si sono rifiutati di includere controlli di base e asserzioni nel codice di produzione, e stiamo continuando a paga il prezzo.)
catch (Throwable t)
. Non vi è alcun motivo per non tentare di intercettare, registrare o riprovare / ripristinare da OutOfMemoryError, AssertionError, ecc.
assert
parola chiave è male. Modificherò la mia risposta per chiarire che mi riferisco alla parola chiave, non al concetto.
Ecco il caso d'uso più comune. Supponiamo di attivare un valore enum:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
}
Finché gestisci ogni caso, stai bene. Ma un giorno qualcuno aggiungerà fico al tuo enum e dimenticherà di aggiungerlo alla tua dichiarazione switch. Questo produce un bug che può essere difficile da rilevare, perché gli effetti non saranno avvertiti fino a quando non avrai lasciato l'istruzione switch. Ma se scrivi l'interruttore in questo modo, puoi prenderlo immediatamente:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
default:
assert false : "Missing enum value: " + fruit;
}
AssertionError
errore se le asserzioni sono abilitate ( -ea
). Qual è il comportamento desiderato in produzione? Un silenzioso no-op e un potenziale disastro più tardi nell'esecuzione? Probabilmente no. Vorrei suggerire un esplicito throw new AssertionError("Missing enum value: " + fruit);
.
default
modo che il compilatore possa avvisarti di casi mancanti. È possibile return
invece break
(potrebbe essere necessario estrarre il metodo) e quindi gestire il caso mancante dopo il passaggio. In questo modo ottieni sia l'avvertimento che l'opportunità di farlo assert
.
Le asserzioni vengono utilizzate per controllare le post-condizioni e le pre-condizioni "non dovrebbero mai fallire". Il codice corretto non dovrebbe mai fallire un'asserzione; quando si innescano, dovrebbero indicare un bug (si spera in un posto vicino a dove si trova il luogo reale del problema).
Un esempio di un'asserzione potrebbe essere quello di verificare che un particolare gruppo di metodi sia chiamato nell'ordine giusto (ad esempio, che hasNext()
è chiamato prima next()
in un Iterator
).
Cosa fa la parola chiave assert in Java?
Diamo un'occhiata al bytecode compilato.
Concluderemo che:
public class Assert {
public static void main(String[] args) {
assert System.currentTimeMillis() == 0L;
}
}
genera quasi lo stesso bytecode esattamente come:
public class Assert {
static final boolean $assertionsDisabled =
!Assert.class.desiredAssertionStatus();
public static void main(String[] args) {
if (!$assertionsDisabled) {
if (System.currentTimeMillis() != 0L) {
throw new AssertionError();
}
}
}
}
dove Assert.class.desiredAssertionStatus()
è true
quando-ea
viene passato dalla riga di comando e false altrimenti.
Ci System.currentTimeMillis()
assicuriamo che non venga ottimizzato (assert true;
fatto).
Il campo sintetico viene generato in modo che Java debba solo chiamare Assert.class.desiredAssertionStatus()
una volta al momento del caricamento e quindi memorizza nella cache il risultato. Guarda anche: Qual è il significato di "sintetico statico"?
Possiamo verificarlo con:
javac Assert.java
javap -c -constants -private -verbose Assert.class
Con Oracle JDK 1.8.0_45, è stato generato un campo statico sintetico (vedi anche: Qual è il significato di "sintetico statico"? ):
static final boolean $assertionsDisabled;
descriptor: Z
flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
insieme a un inizializzatore statico:
0: ldc #6 // class Assert
2: invokevirtual #7 // Method java/lang Class.desiredAssertionStatus:()Z
5: ifne 12
8: iconst_1
9: goto 13
12: iconst_0
13: putstatic #2 // Field $assertionsDisabled:Z
16: return
e il metodo principale è:
0: getstatic #2 // Field $assertionsDisabled:Z
3: ifne 22
6: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
9: lconst_0
10: lcmp
11: ifeq 22
14: new #4 // class java/lang/AssertionError
17: dup
18: invokespecial #5 // Method java/lang/AssertionError."<init>":()V
21: athrow
22: return
Concludiamo che:
assert
: è un concetto di linguaggio Javaassert
potrebbe essere emulato abbastanza bene con le proprietà di sistema -Pcom.me.assert=true
da sostituire -ea
sulla riga di comando e a throw new AssertionError()
.catch (Throwable t)
clausola è in grado di rilevare anche le violazioni delle asserzioni? Per me ciò limita la loro utilità solo nel caso in cui il corpo dell'asserzione richieda tempo, il che è raro.
AssertionError
primo e ripeterlo.
Un esempio del mondo reale, da una classe Stack (da Asserzione in articoli Java )
public int pop() {
// precondition
assert !isEmpty() : "Stack is empty";
return stack[--num];
}
Un'asserzione consente di rilevare difetti nel codice. È possibile attivare le asserzioni per i test e il debug lasciandole fuori quando il programma è in produzione.
Perché affermare qualcosa quando sai che è vero? È vero solo quando tutto funziona correttamente. Se il programma presenta un difetto, potrebbe non essere vero. Rilevarlo prima nel processo ti fa sapere che qualcosa non va.
Un'istruzione assert
contiene questa istruzione insieme a un String
messaggio opzionale .
La sintassi per un'istruzione assert ha due forme:
assert boolean_expression;
assert boolean_expression: error_message;
Ecco alcune regole di base che regolano dove dovrebbero essere usate le asserzioni e dove non dovrebbero essere usate. Le asserzioni dovrebbero essere utilizzate per:
Convalida dei parametri di input di un metodo privato. NON per metodi pubblici. public
i metodi dovrebbero generare eccezioni regolari quando vengono passati parametri errati.
Ovunque nel programma per garantire la validità di un fatto che è quasi certamente vero.
Ad esempio, se sei sicuro che sarà solo 1 o 2, puoi usare un'asserzione come questa:
...
if (i == 1) {
...
}
else if (i == 2) {
...
} else {
assert false : "cannot happen. i is " + i;
}
...
Le asserzioni non devono essere utilizzate per:
Convalida dei parametri di input di un metodo pubblico. Poiché le asserzioni potrebbero non essere sempre eseguite, dovrebbe essere utilizzato il normale meccanismo di eccezione.
Convalida dei vincoli su qualcosa che viene inserito dall'utente. Come sopra.
Non dovrebbe essere usato per effetti collaterali.
Ad esempio, questo non è un uso corretto perché qui l'asserzione viene utilizzata per il suo effetto collaterale della chiamata del doSomething()
metodo.
public boolean doSomething() {
...
}
public void someMethod() {
assert doSomething();
}
L'unico caso in cui ciò potrebbe essere giustificato è quando stai cercando di scoprire se le asserzioni sono abilitate o meno nel tuo codice:
boolean enabled = false;
assert enabled = true;
if (enabled) {
System.out.println("Assertions are enabled");
} else {
System.out.println("Assertions are disabled");
}
Oltre a tutte le ottime risposte fornite qui, la guida ufficiale alla programmazione Java SE 7 ha un manuale piuttosto conciso sull'uso assert
; con diversi esempi chiari di quando è una buona (e, soprattutto, cattiva) idea usare asserzioni e come è diverso dal lanciare eccezioni.
Assert è molto utile durante lo sviluppo. Lo usi quando qualcosa semplicemente non può succedere se il tuo codice funziona correttamente. È facile da usare e può rimanere nel codice per sempre, perché verrà disattivato nella vita reale.
Se c'è qualche possibilità che la condizione possa verificarsi nella vita reale, allora devi gestirla.
Lo adoro, ma non so come accenderlo in Eclipse / Android / ADT. Sembra essere spento anche durante il debug. (C'è un thread su questo, ma si riferisce a 'Java vm', che non appare nella configurazione di esecuzione ADT).
Ecco un'asserzione che ho scritto su un server per un progetto Hibernate / SQL. Un bean di entità aveva due proprietà effettivamente booleane, chiamate isActive e isDefault. Ciascuno potrebbe avere un valore di "Y" o "N" o null, che è stato trattato come "N". Vogliamo assicurarci che il client del browser sia limitato a questi tre valori. Quindi, nei miei setter per queste due proprietà, ho aggiunto questa affermazione:
assert new HashSet<String>(Arrays.asList("Y", "N", null)).contains(value) : value;
Si noti quanto segue.
Questa affermazione è solo per la fase di sviluppo. Se il cliente invia un valore negativo, lo prenderemo presto e lo ripareremo, molto prima di raggiungere la produzione. Le affermazioni riguardano difetti che è possibile rilevare in anticipo.
Questa affermazione è lenta e inefficiente. Va bene. Le affermazioni sono libere di essere lente. Non ci interessa perché sono solo strumenti di sviluppo. Ciò non rallenterà il codice di produzione perché le asserzioni saranno disabilitate. (C'è un certo disaccordo su questo punto, che vedrò più avanti.) Questo porta al mio prossimo punto.
Questa affermazione non ha effetti collaterali. Avrei potuto testare il mio valore contro un Set finale statico non modificabile, ma quel set sarebbe rimasto in produzione, dove non sarebbe mai stato usato.
Questa affermazione esiste per verificare il corretto funzionamento del client. Quindi, quando avremo raggiunto la produzione, saremo sicuri che il cliente funzioni correttamente, in modo da poter disattivare in modo sicuro l'affermazione.
Alcune persone lo chiedono: se l'asserzione non è necessaria nella produzione, perché non toglierli quando hai finito? Perché ne avrai ancora bisogno quando inizi a lavorare alla versione successiva.
Alcune persone hanno sostenuto che non dovresti mai usare asserzioni, perché non puoi mai essere sicuro che tutti i bug siano spariti, quindi devi tenerli in giro anche durante la produzione. E quindi non ha senso usare l'istruzione assert, poiché l'unico vantaggio da asserire è che puoi disattivarli. Quindi, secondo questo pensiero, non dovresti (quasi) mai usare assert. Non sono d'accordo. È certamente vero che se un test appartiene alla produzione, non dovresti usare un'asserzione. Ma questo test no appartiene alla produzione. Questo è per catturare un bug che probabilmente non raggiungerà mai la produzione, quindi potrebbe essere tranquillamente spento quando hai finito.
A proposito, avrei potuto scriverlo in questo modo:
assert value == null || value.equals("Y") || value.equals("N") : value;
Questo vale solo per tre valori, ma se il numero di valori possibili aumenta, la versione di HashSet diventa più conveniente. Ho scelto la versione di HashSet per esprimere il mio punto di vista sull'efficienza.
HashSet
porta un vantaggio di velocità rispetto a una ArrayList
. Inoltre, le creazioni di set ed elenchi dominano il tempo di ricerca. Stanno bene quando usano una costante. Detto questo, +1.
Le asserzioni sono fondamentalmente utilizzate per eseguire il debug dell'applicazione o vengono utilizzate in sostituzione della gestione delle eccezioni per alcune applicazioni per verificare la validità di un'applicazione.
L'asserzione funziona in fase di esecuzione. Un semplice esempio, che può spiegare l'intero concetto in modo molto semplice, è qui: cosa fa la parola chiave assert in Java? (WikiAnswers).
Le asserzioni sono disabilitate per impostazione predefinita. Per abilitarli dobbiamo eseguire il programma con -ea
opzioni (la granularità può essere variata). Ad esempio java -ea AssertionsDemo
,.
Esistono due formati per l'utilizzo delle asserzioni:
assert 1==2; // This will raise an AssertionError
.assert 1==2: "no way.. 1 is not equal to 2";
questo genererà un errore di asserzione con anche il messaggio dato visualizzato ed è quindi migliore. Sebbene la sintassi effettiva sia assert expr1:expr2
dove expr2 può essere qualsiasi espressione che restituisce un valore, l'ho usata più spesso solo per stampare un messaggio.Ricapitolando (e questo vale per molte lingue, non solo per Java):
"assert" viene utilizzato principalmente come aiuto per il debug dagli sviluppatori di software durante il processo di debug. I messaggi di assert non dovrebbero mai apparire. Molte lingue forniscono un'opzione di compilazione che farà ignorare tutti gli "assert", per usarli nella generazione del codice di "produzione".
le "eccezioni" sono un modo pratico per gestire tutti i tipi di condizioni di errore, indipendentemente dal fatto che rappresentino o meno errori logici, perché, se ti imbatti in una condizione di errore tale da non poter continuare, puoi semplicemente "gettarli in aria, "ovunque tu sia, aspettandoti che qualcun altro sia pronto a" catturarli ". Il controllo viene trasferito in un passaggio, direttamente dal codice che ha generato l'eccezione, direttamente al mitt del ricevitore. (E il ricevitore può vedere il backtrace completo delle chiamate che hanno avuto luogo.)
Inoltre, i chiamanti di quella subroutine non devono controllare per vedere se la subroutine è riuscita: "se siamo qui adesso, deve esserci riuscita, perché altrimenti avrebbe gettato un'eccezione e non saremmo qui adesso!" Questa semplice strategia rende molto più semplice la progettazione del codice e il debug.
Le eccezioni consentono convenientemente che le condizioni di errore fatale siano quelle che sono: "eccezioni alla regola". E, per loro, devono essere gestiti da un percorso di codice che è anche "un'eccezione alla regola ... " fly ball! "
Le asserzioni sono assegni che possono essere disattivati. Sono usati raramente. Perché?
result != null
come questi controlli sono molto veloci e non c'è quasi nulla da salvare.Quindi, cosa rimane? Controlli costosi per le condizioni che dovrebbero essere vere. Un buon esempio sarebbero gli invarianti di una struttura di dati come RB-tree. In realtà, in ConcurrentHashMap
JDK8, ci sono alcune affermazioni così significative per il TreeNodes
.
A volte, l'assegno non è molto costoso, ma allo stesso tempo, sei abbastanza sicuro, passerà. Nel mio codice, ad esempio,
assert Sets.newHashSet(userIds).size() == userIds.size();
dove sono abbastanza sicuro che l'elenco che ho appena creato abbia elementi unici, ma volevo documentarlo e ricontrollarlo.
Fondamentalmente, passerà "asserire vero" e "asserire falso" fallirà. Vediamo come funzionerà:
public static void main(String[] args)
{
String s1 = "Hello";
assert checkInteger(s1);
}
private static boolean checkInteger(String s)
{
try {
Integer.parseInt(s);
return true;
}
catch(Exception e)
{
return false;
}
}
assert
è una parola chiave. È stato introdotto in JDK 1.4. Sono due tipi di assert
s
assert
Dichiarazioni molto sempliciassert
Dichiarazioni semplici .Per impostazione predefinita, tutte le assert
istruzioni non verranno eseguite. Se assert
un'istruzione riceve false, genererà automaticamente un errore di asserzione.