2010-04-12 15 views
19

Siete d'accordo che i progettisti della classe Java java.io.IOException avrebbero dovuto fare un'eccezione run-time non controllata derivata da java.lang.RuntimeException invece di un'eccezione controllata derivata solo da java.lang.Exception?La classe IOException in Java deve essere una RuntimeException deselezionata?

Penso che la classe IOException avrebbe dovuto essere un'eccezione non controllata perché c'è poco che un'applicazione può fare per risolvere problemi come errori del file system. Tuttavia, in When You Can't Throw An Exception, Elliotte Rusty Harold affermazioni che più errori I/O sono transitori e in modo da poter ripetere un'operazione di I/O diverse volte prima di rinunciare:

Per esempio, un IOComparator potrebbe non prendere un I/O error sdraiati, ma - perché molti problemi di I/O sono transitoria - è possibile riprovare un paio di volte, come mostrato nel Listato 7:

è questo generalmente il caso? Un'applicazione Java può correggere errori di I/O o attendere il ripristino del sistema? In tal caso, è ragionevole verificare IOException, ma se non è il caso, quindi IOException deve essere deselezionato in modo che la logica aziendale possa delegare la gestione di questa eccezione a un gestore di errori di sistema separato.

+12

Molte persone pensano che OGNI eccezione avrebbe dovuto essere senza controllo ... – leonbloy

+4

Molte persone hanno bisogno di prendere in considerazione che le eccezioni hanno Vuoi sapere che potrebbe accadere. –

+3

@ Thorbjørn: Dubito che sia una coincidenza che nessun'altra lingua abbia copiato il modello di eccezione chekced. È stato un esperimento interessante, suona bene in teoria, ma fa molto più male che bene nella pratica. –

risposta

16

Sono completamente in disaccordo. Per me la modella è corretta. Una RuntimeException è quella che più tipicamente denota un errore grave nella logica della programmazione (come ArrayIndexOutOfBounds, NullPointer o IllegalArgument) o qualcosa che il runtime ha determinato diversamente in realtà non dovrebbe accadere (come SecurityException).

Viceversa IOException e le sue derivate sono eccezioni che potrebbero ragionevolmente verificarsi durante la normale esecuzione di un programma, e una logica comune imporrebbe che questi problemi debbano essere affrontati, o almeno il programmatore dovrebbe essere consapevole che possono verificarsi. Ad esempio con File se il tuo logger dell'applicazione non può scrivere i suoi dati, preferiresti essere costretto a catturare una potenziale IOException e recuperare, o avere qualcosa che potrebbe non essere critico per la tua app abbattere l'intera JVM perché nessuno ha pensato di catturare il Eccezione deselezionata (come avrai intuito, sceglierò la prima).

Penso che ci siano molte situazioni in cui una IOException può essere ripristinata, o almeno il programmatore dovrebbe essere esplicitamente a conoscenza del potenziale in modo che se non è ripristinabile il sistema potrebbe essere in grado di bloccarsi di più "delicatamente" .

Per quanto riguarda il fatto che il sistema non è in grado di ripristinare ci sono sempre alternative con un'eccezione controllata. Si può sempre avere i vostri metodi dichiarano nel loro tiri liberi, un'eccezione di runtime del proprio o di mandare in crash la JVM con violenza:

public void doit() throws IOException { 
    try{ 
    }catch(IOException e){ 
    // try to recover 
    ... 

    // can't recover 
    throw e; 
    } 
} 

public void doit() { 
    try{ 
    }catch(IOException e){ 
    // try to recover 
    ... 

    // can't recover 
    throw new RuntimeException(e); 
    } 
} 



public void doit() { 
    try{ 
    }catch(IOException e){ 
    // try to recover 
    ... 

    // OH NO!!!! 
    System.exit(Constant.UNRECOVERABLE_IO_ERROR); 
    } 
} 
+6

In http://www.oracle.com/technology/pub/articles/dev2arch/2006/11/effective-exceptions.html, Barry Ruzek non è d'accordo: "Un guasto I/O è un evento serio ma estremamente raro. di questo, di solito non c'è nulla che il tuo codice possa fare per recuperare da uno. " Secondo Ruzek, molte librerie Java lanciano questa eccezione, suggerendo che seguono il tuo primo approccio al recupero da una 'IOException'. Tuttavia, se qualche metodo non riesce a recuperare da un 'IOException', qual è il punto di gettarlo più in alto quando è improbabile che il client possa comunque recuperare? –

+5

Non sono d'accordo con eventi "estremamente rari". Considera una presa di rete. È del tutto ragionevole che uno Socket del client si disconnetta e se si sta tentando di scrivere o leggere i dati ciò causerà un'eccezione IOException. Per il recupero penso che tu debba stare attento alla tua definizione di "recupero". Nell'esempio del socket si potrebbe perdere la connessione client, ma il ripristino potrebbe essere un processo come liberare risorse utilizzate dalla connessione interrotta. Allo stesso modo per il rethrowing potresti voler registrare l'evento vicino al mittente, ma consentire a qualcosa di più in alto nello stack di affrontarlo. –

+0

Quindi, in tal caso, si consiglia di rilanciare un 'RuntimeException' dopo il ripristino non riesce? Questo non è leggermente diverso (e altrettanto brutto) di un 'IOException 'non controllato? –

2

No perché è possibile ripristinare da alcune IOException. I più importanti sono letture e scritture indicizzate a basso livello. Se fallisce, a volte puoi semplicemente riprovare senza danno.

5

penso che sia intelligente per lasciare un eccezione controllata. Considero le eccezioni di runtime come bug, e chiaramente non è il caso. Talvolta è possibile il recupero tramite tentativi e anche alcuni messaggi IOException possono essere informativi per l'utente finale (ad esempio, nessuna autorizzazione per scrivere, spazio su disco insufficiente, ecc.).

+1

Considero le eccezioni controllate come un ** bug ** nella progettazione della lingua. Lo dici tu stesso: un messaggio IOExcpetion può essere informativo per l'utente, ma a che serve il metodo IO di basso livello che non ha business con l'interfaccia utente e che tuttavia è costretto a rilevare l'eccezione oa inquinare la sua firma con esso? –

+0

Michael, vuoi dire che il metodo I/O di basso livello è forzato a catturare l'eccezione e inquinare la sua firma, o il codice di livello dell'interfaccia utente? –

+2

@ Michael: IMO la firma non è affatto inquinata. Proprio come si specifica il tipo di valore restituito, è necessario specificare anche altri tipi di risultati legittimi dell'azione. Ha un'importanza sia pratica che dichiarativa. –

3

Probabilmente la maggior parte delle eccezioni IO è recuperabile: errori di autorizzazione, mancanza di spazio sull'unità, connessione chiusa, ecc. Ecc.Credo che le eccezioni non controllate debbano essere utilizzate per "non esiste un modo ragionevole per recuperare da questo" tipo di situazioni.

1

In un quadro di eccezioni ben progettato, occorre fare una distinzione tra eccezioni che sono in una certa misura "previste" e quelle che non lo sono. Java tenta di utilizzare le eccezioni controllate e non controllate per questo. Secondo questo standard, IOException dovrebbe essere un'eccezione controllata.

Un problema fondamentale, tuttavia, è che spesso il codice verrà scritto con una (forse ragionevole) aspettativa che una certa eccezione non si verifichi e nulla può essere fatto utilmente per gestirlo se lo fa. Se un metodo viene dichiarato come lancio di una particolare eccezione verificata, Java consente al chiamante di ignorare l'eccezione se si dichiara di lanciare quell'eccezione, ma non c'è modo in cui un metodo o un blocco di codice possa specificare che certe eccezioni dai metodi chiamati siano non dovrebbe verificarsi. Un anti-modello comune è:

try 
{ 
    methodThatsDeclaredAsThrowingFooExceptionButWont() 
} 
catch FooException Ex 
{ 
    // Never going to happen 
} 

Il presupposto evidente è che, poiché il metodo non getterà FooException e l'unico motivo per il catch c'è è quello di rendere il compilatore felice, non c'è alcun motivo per il catch da fare nulla. Insidioso, perché se un FooException viene lanciato, per qualsiasi motivo, non verrà rilevato.

Un'alternativa è per un metodo che chiama methodThatsDeclaredAsThrowingFooExceptionButWont per dichiararsi come throws FooException o throws Exception, ma anche questo non è proprio appropriato. Se un metodo che non è previsto per il lancio di un FooException, lo stato del sistema è adatto per essere diverso da quello che ci si aspetterebbe quando viene lanciato un FooException.

Ad esempio, si supponga di voler caricare un documento, ma la routine di caricamento del documento deve leggere alcune tabelle di traduzione non specifiche del documento che devono essere memorizzate in una posizione fissa; se il tentativo fallisce, avere il percolato fino al chiamante IOException implicherebbe che si è verificato un problema nel caricare il documento che si sta caricando. Se la routine load-document non è preparata a gestire in modo ragionevole la possibilità che la routine load-translation-tables possa fallire, tale errore non dovrebbe percolarsi allo stesso modo di un IOException che si è verificato durante il caricamento del documento.

Il rimedio appropriato non sarebbe per IOException essere un'eccezione incontrollato, ma piuttosto per lì per essere un mezzo dichiarative attraverso il quale il codice potrebbe indicare che uno o più tipi di eccezioni controllate, non dovrebbe essere consentito di percolato di una certa blocco dai metodi chiamati in tal modo, ma dovrebbe invece essere racchiuso in qualche altro tipo di eccezione (ad es. RuntimeException).

9

so che è stato 4 anni da quando questa domanda è stato chiesto, ma un UncheckedIOException è stato aggiunto in Java 8.

+3

I designer dell'API Java 8 devono aver letto la mia domanda! Con il senno di poi, avrei dovuto inventare "UncheckIOException" me stesso e protetto da copyright l'API in modo che Oracle avrebbe dovuto pagarmi le tasse di licenza. :) –

Problemi correlati