Come gestire le eccezioni verificate che non possono mai essere lanciate


35

Esempio:

foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");

Poiché la codifica è codificata e corretta, il costruttore non genererà mai l'UnsupportedEncodingException dichiarata nelle specifiche (a meno che l'implementazione java non venga interrotta, nel qual caso mi perdo comunque). Comunque, Java mi costringe a gestire comunque quell'eccezione.

Attualmente sembra così

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
}
catch(UnsupportedEncodingException e) { /* won't ever happen */ }

Qualche idea su come migliorarlo?


4
Per una vera sfida, scrivi un test unitario per assicurarti che questo fermo funzioni davvero.
Jay Elston,

1
`buttare nuova ImpossibleException (" Riavvia l'universo. Le cose sono incasinate ", e);
Chris Cudmore,

1
"Non accadrà mai" sarà ...

Thorbjørn Ravn Andersen: potrebbe dopo aver cambiato il programma, ma almeno nel suo stato attuale, nessuna serie di dati di input può attivare l'eccezione.
user281377

Nel tuo esempio specifico sopra, viene generata un'eccezione perché il metodo non sa se verrà chiamato con una codifica supportata o non supportata. Un modo per aggirare questo sarebbe se ci fosse un altro costruttore che ha assunto un set di caratteri standard, che non avrebbe bisogno di dichiarare che sarebbe stata lanciata un'eccezione.
Giordania,

Risposte:


27

La mia abitudine è, solo per essere al sicuro, di inserire un assertblocco di cattura. Qualcuno potrebbe cambiare il contenuto del tryblocco in un secondo momento, e vuoi sapere se il codice fallisce, vero?


Buona idea; un semplice assert false;non aggiunge troppo ingombro e chiarisce che presumo che il blocco catch non verrà mai inserito.
user281377

5
@ammoQ, o si può anche aggiungere un messaggio per rendere il vostro intento assolutamente chiaro: assert false : "should never happen".
Péter Török,

13
Ancora meglio, "Non dovrebbe mai accadere perché Java richiede il set di caratteri ISO-8859-1 per essere supportato."
dan04,

3
assertimplica che le asserzioni sono abilitate. Lancio un UnexpectedException(che ha anche il vantaggio di farmi avere una traccia dello stack ...).
Taglia il

35

Se mi fosse stato dato un centesimo ogni volta che vedevo un log / errore, "Questo non dovrebbe mai accadere", avrei ... beh, due centesimi. Ma comunque ...

I blocchi di cattura vuoti fanno formicolare il mio ragno e si lamentano la maggior parte degli strumenti di analisi del codice. Eviterei a tutti i costi di lasciarli vuoti. Certo, ora sai che l'errore non può mai accadere, ma tra un anno qualcuno farà una sostituzione globale della ricerca di "ISO-8859-1" e improvvisamente potresti avere un bug estremamente difficile da trovare.

Il assert falsesuggerimento è buono, ma poiché le asserzioni possono essere disabilitate in fase di esecuzione, non sono garantite. Userei RuntimeExceptioninvece un . Questi non dovranno essere catturati chiamando le classi e se mai si verificheranno avrai una traccia dello stack per fornire informazioni complete.


28

L'ho sempre fatto così:

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
} catch(UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

Può essere un po 'prolisso (Java è ...), ma almeno otterrai un errore di asserzione quando l'impossibile accade.

Se l'implementazione di Java viene interrotta, ti consigliamo di ricevere il miglior messaggio di errore il più rapidamente possibile, invece di ignorare l'impossibile. E anche se l'implementazione Java non viene interrotta, qualcuno potrebbe aver modificato il codice in "UTF8"(oops - avrebbe dovuto essere "UTF-8"?).

In primo luogo, questa dovrebbe essere stata un'eccezione di runtime. JDK è pieno di questo tipo di scelte sbagliate.


4
La vera cattiva decisione (o omissione se lo si desidera) è che non ci sono istanze Charset predefinite per quei 6 set di caratteri richiesti da Java. foobar = new InputStreamReader(p.getInputStream(), Charset.ISO_8859_1);- ora non sarebbe più bello ed evitare qualsiasi errore una volta per sempre?
user281377

3
La biblioteca di Guava ha tonnellate di queste cose. Semplifica la vita.

3
Java 1.7+ ha costanti charset definite: docs.oracle.com/javase/7/docs/api/java/nio/charset/… . Usali in questo modo: StandardCharsets.UTF_8.displayName ()
Michael

4

Se sei l'unico sviluppatore che potrà mai vedere questo codice, allora direi che va bene, ma se non lo sei, lo tratterei come una possibilità reale o almeno cambierei il commento "non accadrà mai" in qualcosa di più utile.


4

La parte di queste eccezioni che mi infastidisce di più è che danneggia la copertura del mio codice.

Quando sto diventando compulsivo riguardo alla copertura, arrotolerò il tentativo / cattura che "non potrà mai accadere" (... o solo se sto usando una JVM mutante che in qualche modo ha dimenticato di includere "US-ASCII") in una classe e un metodo che incapsula quel try / catch e sostituiscono l'eccezione controllata in uno dei modi menzionati qui (di solito lanciando un'eccezione non selezionata con un messaggio snide).

Quindi la mia copertura del codice ha un successo nella classe di utilità, ma non in tutti i riferimenti a quell'operazione sparsi per il mio codice.

A volte mi prenderò il tempo di rimboccarmi come operazioni in una classe che in realtà ha una semantica coerente. Ma poiché è abbastanza ovvio per i miei compagni di squadra cosa sta succedendo, di solito lo mantengo il più semplice possibile e non mi preoccupo così tanto del miglior design possibile.

Tuttavia, come menzionato in un commento, Guava e altre biblioteche hanno modi per mitigare questo dolore, ma questa è sostanzialmente la stessa strategia. Sposta il fastidio fuori dal palco in modo che il tuo codice principale non subisca il colpo in copertura.

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.