2016-05-11 57 views
10

L'immagine seguente mostra che le eccezioni "Controllato" e "Non selezionato" sono sottoclassi di Exception. Trovo confuso il fatto che è necessario prendere uno Exception ma non è necessario prendere uno RuntimeException, che eredita direttamente da Exception. C'è una ragione per cui gli sviluppatori non ci hanno permesso di lanciare Eccezioni senza aver bisogno di catturarle?Perché è necessario rilevare "Eccezione" ma non la Sottoclasse "RuntimeException"?

In particolare: perché si può ignorare solo RuntimeExceptions ed è bambini? Perché non c'era una classe introdotta chiamata CheckedException extends Exception e devi solo prenderla e sono i bambini?

La parte confusa è che è possibile lanciare tutto sotto lo RuntimeException senza problemi, ma quando ci si sposta fino a Exception nella gerarchia, è necessario catturarlo a un certo punto. Ciò è fonte di confusione perché "l'astrazione" normalmente funziona diversamente. Più ti muovi, più semplice e più diventa tutto. Questo non è il caso qui. Più ti muovi, più devi fare (tipo mettere try/catch dopo aver raggiunto Exception).

enter image description here

+0

ho pensato che se si cattura 'Exception' che si prenderà tutte le eccezioni e le eventuali discendenti di tale eccezione classe pure? –

+0

Per qualsiasi ragione i progettisti di Java pensavano che le eccezioni controllate fossero una buona idea, hanno anche deciso che tutti i 'Throwable's dovrebbero essere controllati di default, a meno che non siano specificatamente esclusi dalla sottoclasse' Error' o 'RuntimeException'. – shmosel

risposta

1

CheckedException (Il che non esiste) e RuntimeException entrambi estendono Exception. Per questo motivo, se qualcosa genera un generico Exception (che è sempre una cattiva idea), non c'è modo di sapere se l'eccezione potrebbe essere l'una o l'altra, quindi devi prenderla nel caso sia selezionata. Se si pensa alla gerarchia in questo modo, in realtà fa più semplicemente più si va avanti.

Sembra che tu abbia l'idea che le eccezioni controllate siano più "complesse" perché devi fare di più per aggirarle. Questo non è un modo di pensare troppo sano. Invece, considera questo: le eccezioni sono problemi con il programma stesso - il codice. Dobbiamo trovare queste eccezioni e gestirle correttamente. Dopo aver già avuto questo concetto di gestione delle eccezioni, scopriamo che ci sono alcuni problemi che semplicemente non possiamo prevedere.

"Come avrei dovuto sapere che l'utente avrebbe inserito" meow "quando gli è stato chiesto un numero intero? Non avrei dovuto codificare tutto ciò!" E così, è nato NumberFormatException, e non devi prenderlo perché è un "errore logico", non un problema causato da codice errato (anche se, probabilmente, potrebbe essere considerato un codice errato se non gestisci questa situazione in qualche modo).

In breve, invertire il tuo pensiero. Exception s sono problemi con il programma che può essere gestito. Ci sono alcune eccezioni, tuttavia, che sono impreviste e sono il risultato di una progettazione errata più che di un codice errato. Quindi c'è l'aggiunta di RuntimeException s che non si può prevedere che si verifichi, ma che può certamente verificarsi.

4

Supponiamo che l'abbiano progettato nell'altro senso. Abbiamo una classe CheckedException e le sottoclassi di tale necessità da gestire, ma non altre sottoclassi di Exception.

Ora abbiamo chiamare un metodo che potrebbe gettare un arbitrario Exception:

public static void example() { 
    functionThatThrowsException(); 
} 

abbiamo bisogno di gestire la cosa? , perché quello Exception potrebbe essere un CheckedException. Se non avessimo bisogno di gestirlo, ignoreremmo la natura verificata delle eccezioni controllate.

Un tipo di lancio con i discendenti controllati deve essere considerato come controllato, quindi la verifica si propaga naturalmente sulla gerarchia dell'ereditarietà. Contra-positivamente, un tipo di ganci non controllato non può aver controllato i discendenti, quindi la non verificabilità si propaga naturalmente verso il basso. Ciò rende naturale verificare l'impostazione predefinita e separare le classi specifiche ei loro discendenti come deselezionati.

+0

E se CheckedExceptions fosse completamente separato? Non ereditando da Eccezione? Sembrerebbe strano, ma eliminerebbe anche la situazione. Non che io pensi che questo sia un problema o meno, ma non so.Capisco le spiegazioni ma non mi sembrano come se forzassero necessariamente un disegno come quello attuale. – codepleb

+0

@TrudleR: Quindi catturare tutte le eccezioni (ma non cose come ThreadDeath) avrebbe richiesto due blocchi catch. (Questo era prima della sintassi '|' per catturare più tipi di eccezioni.) La struttura attuale non è una situazione indesiderabile che deve essere forzata, quindi non ha senso cercare di trovare un motivo che sarebbe stato abbastanza forte da forzarlo . È solo leggermente più naturale in questo modo. – user2357112

1

Forse sarebbe utile non pensare alle classi di eccezioni in termini di ereditarietà ma semplicemente disgiungere serie di classi, un set è controllato e altro no. Hai ragione che potrebbe esserci una classe CheckedException che ci consente di controllare solo se esplicitamente inteso.

Tuttavia, avere il campo più ampio/generalizzato controllato aiuta a far rispettare la sequenza catch or specify. Avendo controllato l'eccezione consente a un lettore del codice di capire rapidamente che questa parte di codice richiede un'attenzione speciale e impone la loro gestione in fase di compilazione riducendo i bug di runtime.

Possiamo lanciare qualsiasi tipo di eccezione, selezionata o deselezionata. Se Exception o qualsiasi super classe di RuntimeException dovessero essere impostati come eccezione verificata, tutte le sottoclassi diventerebbero eccezioni controllate. Molto probabilmente il compilatore controlla se un'istanza di eccezione o una classe nella clausola throws deriva da una classe. Avrebbe potuto facilmente farlo controllando la presenza di un pacchetto specifico che probabilmente sarebbe stato più appropriato in quanto essere controllato o deselezionato semplicemente non ha nulla a che fare con l'ereditarietà.

5

Se Exception era incontrollato, allora si potrebbe implicitamente lanci eccezioni controllate a quelli non controllati, il che significherebbe che si potrebbe buttare eccezioni controllate senza prendere loro come:

public void f() { 
    Exception e = new IOException(); 
    throw e; 
} 

e anche con i metodi di primaria importanza, se si lancia una più specifica eccezione, è possibile aggiungere l'obbligo di intercettare l'eccezione che non era nella superclasse:

public void f() throws Exception { 
} 

... 

@Override 
public void f() throws IOException { 
} 
+1

Ma con questo, si potrebbe anche dire, 'Exception e = new RuntimeException()' che dovrebbe essere catturato senza motivo. Se qualcuno fa quello che mostri, non sarebbe in qualche modo "di proposito"? Con esattamente quell'intenzione (per qualunque ragione). Le persone possono sempre fare cose cattive di proposito, se lo desiderano. – codepleb

1

la vostra immagine contiene già una risposta - Throwable sia selezionata e deve essere catturato, a causa di questo, Exception viene controllato e così via, oltre allo RuntimeException e ai suoi discendenti.

Eccezioni controllate devono essere intercettate o riconfigurate (JLS §11.2). Questo è garantito dal compilatore java, così ci assicureremo che la nostra situazione "eccezionale" sarà gestita.

Questa fase di compilazione verificare la presenza di gestori di eccezioni è progettati per ridurre il numero di eccezioni che non sono correttamente maneggiato.

Se invertire la logica, allora non si può dare queste garanzie in fase di compilazione:

public void notReallySafeMethod() { 
    try { 
     connect(); 
    } catch (IOException io) { 
     Exception e = io; 
     throw e; // IOException is unhandled 
    } 
} 

public void suspiciousMethod() throws Exception {}; 

public void callSuspicious() { 
    suspiciousMethod(); // what real type would be thrown? we can't know 
    // should I try-catch everything then? 
}