Comprensione delle eccezioni verificate rispetto a quelle non selezionate in Java


703

Lo ha detto Joshua Bloch in " Efficace Java "

Utilizzare le eccezioni verificate per le condizioni recuperabili e le eccezioni di runtime per errori di programmazione (elemento 58 nella seconda edizione)

Vediamo se lo capisco correttamente.

Ecco la mia comprensione di un'eccezione controllata:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. Quanto sopra è considerato un'eccezione controllata?

2. RuntimeException è un'eccezione non selezionata?

Ecco la mia comprensione di un'eccezione non selezionata:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. Ora, anche il codice sopra riportato non può essere un'eccezione controllata? Posso provare a recuperare la situazione in questo modo? Posso? (Nota: la mia terza domanda è all'interno di quanto catchsopra)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. Perché le persone fanno questo?

public void someMethod throws Exception{

}

Perché fanno esplodere l'eccezione? La gestione dell'errore non è migliore prima? Perché bolle?

6. Devo eliminare l'esatta eccezione o mascherarla utilizzando l'eccezione?

Di seguito sono le mie letture

In Java, quando dovrei creare un'eccezione controllata e quando dovrebbe essere un'eccezione di runtime?

Quando scegliere le eccezioni selezionate e non selezionate


6
Ho un ottimo esempio di eccezione non selezionata. Ho una DataSeriesclasse che contiene dati che devono sempre rimanere in ordine temporale. C'è un metodo per aggiungere un nuovo DataPointalla fine di a DataSeries. Se tutto il mio codice funziona correttamente in tutto il progetto, DataPointnon si dovrebbe mai aggiungere un alla fine che ha una data precedente a quella già alla fine. Ogni modulo dell'intero progetto è costruito con questo principio. Tuttavia, controllo questa condizione e, se accade, genera un'eccezione non selezionata. Perché? Se succede, voglio sapere chi lo sta facendo e risolverlo.
Erick Robertson,

3
Per aggiungere ancora più confusione. Molte persone sostenevano le eccezioni verificate ~ 10 anni fa, ma la visione al giorno d'oggi si sta spostando sempre più verso "le eccezioni controllate sono cattive". (Tuttavia non sono d'accordo)
Kaj,

10
È utile solo per gestire un'eccezione quando hai qualcosa di utile a che fare con essa, altrimenti dovresti lasciare che sia il chiamante a gestirla. Registrarlo e fingere che non sia accaduto di solito non è utile. Il solo lancio è inutile. Il wrapping in RuntimeException non è così utile come alcuni pensano, ma fa semplicemente smettere il compilatore di aiutarti. (IMHO)
Peter Lawrey,

40
Dovremmo smettere di usare i termini completamente fuorvianti delle eccezioni controllate / non controllate . Essi dovrebbero essere chiamati check-mandato vs check-non-mandato eccezioni.
Beato Geek,

3
Ho anche pensato che il tuo nullo metodo pubblico del 5 ° punto genera l'eccezione {} perché alcune persone lo fanno?
Maveň

Risposte:


474

Molte persone affermano che le eccezioni verificate (ovvero quelle che dovresti catturare o rilanciare esplicitamente) non dovrebbero essere affatto utilizzate. Sono stati eliminati in C # per esempio, e la maggior parte delle lingue non li ha. Quindi puoi sempre generare una sottoclasse di RuntimeException(eccezione non selezionata)

Tuttavia, ritengo che le eccezioni verificate siano utili: vengono utilizzate quando si desidera forzare l'utente dell'API a pensare a come gestire la situazione eccezionale (se recuperabile). È solo che le eccezioni controllate sono abusate nella piattaforma Java, il che fa sì che le persone le odino.

Ecco la mia visione estesa sull'argomento .

Per quanto riguarda le domande particolari:

  1. È la NumberFormatExceptionconsiderano un'eccezione controllata?
    No. NumberFormatExceptionè deselezionato (= è la sottoclasse di RuntimeException). Perché? Non lo so. (ma avrebbe dovuto esserci un metodo isValidInteger(..))

  2. È RuntimeExceptionun'eccezione incontrollato?
    Si, esattamente.

  3. Cosa dovrei fare qui?
    Dipende da dove si trova questo codice e da cosa vuoi che accada. Se si trova nel livello dell'interfaccia utente, prendilo e mostra un avviso; se è nel livello di servizio - non prenderlo affatto - lascialo bolle. Basta non ingoiare l'eccezione. Se si verifica un'eccezione nella maggior parte dei casi, è necessario scegliere uno di questi:

    • registralo e ritorna
    • riprovalo (dichiaralo per essere lanciato con il metodo)
    • costruire una nuova eccezione passando quella corrente nel costruttore
  4. Ora, anche il codice sopra non può essere un'eccezione controllata? Posso provare a recuperare la situazione in questo modo? Posso?
    Avrebbe potuto essere Ma nulla ti impedisce di cogliere anche l'eccezione non selezionata

  5. Perché le persone aggiungono classe Exceptionnella clausola dei tiri?
    Molto spesso perché le persone sono pigre a considerare cosa catturare e cosa ripensare. Lanciare Exceptionè una cattiva pratica e dovrebbe essere evitato.

Purtroppo, non esiste una singola regola che ti consenta di stabilire quando catturare, quando ricodificare, quando utilizzare la casella di controllo selezionata e quando utilizzare le eccezioni non selezionate. Sono d'accordo che questo provoca molta confusione e un sacco di codice negativo. Il principio generale è affermato da Bloch (ne hai citato una parte). E il principio generale è quello di riproporre un'eccezione al livello in cui è possibile gestirlo.


36
Per quanto riguarda il lancio dell'eccezione, non è sempre perché le persone sono pigre, ma è anche comune che, quando si implementano i framework, gli utenti del framework siano in grado di lanciare qualsiasi eccezione. Ad esempio, è possibile verificare la firma dell'interfaccia Callable in JSE
Kaj,

10
@Kaj - sì, cose del genere come Callable, intercettori e simili sono casi speciali. Ma nella maggior parte dei casi è perché le persone sono pigre :)
Bozho,

7
ri: 3.1 "registralo e ritorna" Fallo in modo giudizioso. Questo è molto vicino a mangiare o nascondersi ed eccezione. Lo farei per qualcosa che non indica un problema, che non è davvero eccezionale. I log vengono allagati e ignorati troppo facilmente.
Chris,

4
"quando vuoi forzare l'utente della tua API a pensare a come gestire la situazione eccezionale" - non puoi costringere nessuno a pensare se non lo desidera. Se non vogliono pensare, scriveranno un blocco delle eccezioni scadente che non fa nulla, o peggio, elimina o interferisce con le informazioni di errore critiche. Ecco perché le eccezioni controllate sono un errore.
adrianos,

3
@adrianos "... non puoi costringere nessuno a pensare se non vogliono ..." Con questa linea di pensiero potremmo anche rimuovere gli errori di compilazione .... Non ti sto prendendo di mira, ho sentito questo argomento più volte e ancora trovo che sia la spiegazione più povera possibile per etichettare le eccezioni controllate come un fallimento. Come nota a margine, ho visto prima un linguaggio del genere in cui la compilazione (e anche gli errori di runtime) erano effettivamente resi impossibili dal desing. Quella strada conduceva in posti molto bui.
Newtopian,

233

Il fatto che qualcosa sia "un'eccezione controllata" non ha nulla a che fare con il fatto che tu la catturi o che cosa fai nel blocco catch. È una proprietà di classi di eccezioni. Tutto ciò che è una sottoclasse di Exception tranne per RuntimeExceptione le sue sottoclassi è un'eccezione controllata.

Il compilatore Java ti costringe a catturare le eccezioni verificate o a dichiararle nella firma del metodo. Doveva migliorare la sicurezza del programma, ma l'opinione della maggioranza sembra essere che non valga la pena creare problemi di progettazione.

Perché fanno esplodere l'eccezione? Non gestire l'errore prima è, meglio è? Perché bolle?

Perché questo è l'intero punto delle eccezioni. Senza questa possibilità, non avresti bisogno di eccezioni. Ti consentono di gestire gli errori a un livello che scegli, anziché forzarti a gestirli con metodi di basso livello in cui si verificano in origine.


3
Grazie! Occasionalmente lancio eccezioni dai miei metodi a causa del principio di schifo in crape out. Uno degli sviluppatori del mio team desidera inserire un'espressione xpath non valida che spetta a loro per gestire l'eccezione. Nell'improbabile eventualità che prendano un'eccezione e non fanno nulla di cui sentiranno parlare nella revisione del codice.
jeremyjjbrown,

12
"Tutto ciò che è una sottoclasse di Throwable ad eccezione di RuntimeException e delle sue sottoclassi è un'eccezione verificata." - La tua affermazione non è corretta. L'errore eredita anche Throwable ed è deselezionato.
Bartzilla,

8
@JonasEicher: fondamentalmente, un vantaggio principale delle eccezioni è che ti permettono di scegliere dove nello stack di chiamate vuoi gestire gli errori, che è spesso abbastanza alto, mantenendo i livelli completamente liberi da artefatti di gestione degli errori. Le eccezioni verificate distruggono esattamente quel vantaggio. Un altro problema è che la distinzione selezionata / deselezionata è legata alla classe di eccezione che rappresenta anche una categorizzazione concettuale delle eccezioni, mescolando due aspetti che non sono necessariamente correlati affatto.
Michael Borgwardt,

2
"ma l'opinione della maggioranza sembra essere che non valga la pena creare problemi di progettazione". - Per favore citazione?
Kervin,

3
@Bartzilla Sì. Per completezza, come Throwabledice il javadoc : "Gettabile e qualsiasi sottoclasse di Gettabile che non è anche una sottoclasse di RuntimeException o Error sono considerati eccezioni controllate"
Bart van Heukelom,

74
  1. Quanto sopra è considerato un'eccezione controllata? No Il fatto che si stia gestendo un'eccezione non la rende a Checked Exceptionse è a RuntimeException.

  2. È RuntimeExceptionun unchecked exception? sì

Checked Exceptionssono subclassesdi java.lang.Exception Unchecked Exceptionssono subclassesdijava.lang.RuntimeException

Le chiamate che generano eccezioni verificate devono essere racchiuse in un blocco try {} o gestite a un livello superiore nel chiamante del metodo. In tal caso, l'attuale metodo deve dichiarare che genera dette eccezioni in modo che i chiamanti possano prendere le disposizioni appropriate per gestire l'eccezione.

Spero che sia di aiuto.

D: dovrei eseguire il bubble up dell'eccezione esatta o mascherarla usando l'eccezione?

A: Sì, questa è un'ottima domanda e un'importante considerazione progettuale. La classe Exception è una classe di eccezioni molto generale e può essere utilizzata per racchiudere eccezioni interne di basso livello. Faresti meglio a creare un'eccezione personalizzata e racchiuderla al suo interno. Ma, e grande, mai e poi mai oscuro nella causa originale alla base. Ad esempio, Don't everfai quanto segue -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Invece fai quanto segue:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Eliminare la causa principale originale seppellisce la causa effettiva oltre il recupero è un incubo per i team di supporto alla produzione in cui tutti hanno accesso ai registri delle applicazioni e ai messaggi di errore. Sebbene quest'ultimo sia un design migliore, ma molte persone non lo usano spesso perché gli sviluppatori non riescono a trasmettere il messaggio sottostante al chiamante. Quindi prendi nota con fermezza: Always pass on the actual exceptiontorna indietro se incluso in un'eccezione specifica dell'applicazione.

Alla prova RuntimeExceptions

RuntimeExceptions come regola generale non dovrebbe essere preso alla sprovvista. Generalmente segnalano un errore di programmazione e dovrebbero essere lasciati soli. Invece il programmatore dovrebbe verificare la condizione di errore prima di invocare un codice che potrebbe comportare un RuntimeException. Ad esempio:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Questa è una cattiva pratica di programmazione. Invece un controllo null avrebbe dovuto essere fatto come -

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Ma ci sono momenti in cui tale controllo degli errori è costoso come la formattazione dei numeri, considera questo:

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

In questo caso il controllo degli errori pre-invocazione non vale la pena, perché essenzialmente significa duplicare tutto il codice di conversione da stringa a intero all'interno del metodo parseInt () - ed è soggetto a errori se implementato da uno sviluppatore. Quindi è meglio eliminare semplicemente try-catch.

Quindi, NullPointerExceptione NumberFormatExceptionsono entrambi RuntimeExceptions, la cattura di un NullPointerExceptiondovrebbe essere sostituita da un grazioso controllo null mentre raccomando di catturare NumberFormatExceptionesplicitamente un per evitare la possibile introduzione di codice soggetto a errori.


Grazie. Un'altra domanda quando fai gorgogliare il exception, dovrei fare il bubble up dell'esatta eccezione o mascherarla usando Exception. Sto scrivendo il codice sopra un po 'di codice legacy ed Exceptionessendo gorgogliato dappertutto. Mi chiedo se questo è il comportamento corretto?
Thang Pham,

1
Questa è una domanda molto buona e importante, modificata la mia risposta per includere la spiegazione.
d-live

Grazie mille. Potresti mostrarmi il contenuto di LoginFailureException(sqle)?
Thang Pham,

1
Non ho alcun codice per quella roba, ho appena inventato i nomi ecc. Se vedi java.lang.Exception, ha 4 costruttori di cui due accettano java.lang.Throwable. In frammenti sopra ho assunto l' LoginFailureExceptionestensione Exceptione dichiara un costruttorepublic LoginFailureException(Throwable cause) { super(cause) }
d-live

La migliore risposta sull'argomento. Penso che le eccezioni di runtime non debbano essere colte perché queste eccezioni si verificano a causa della mancanza di una buona programmazione. Sono completamente d'accordo con la parte "Eliminare la causa principale originale seppellendo la causa effettiva oltre il recupero è un incubo per i team di supporto alla produzione in cui tutti hanno accesso ai registri delle applicazioni e ai messaggi di errore".
huseyin,

19

1 Se non sei sicuro di un'eccezione, controlla l'API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2 Sì, e ogni eccezione che lo estende.

3 Non è necessario catturare e lanciare la stessa eccezione. In questo caso puoi mostrare una nuova finestra di dialogo File.

4 FileNotFoundException è già un'eccezione controllata.

5 Se si prevede che il metodo che chiama someMethodper catturare l'eccezione, quest'ultimo può essere lanciato. Semplicemente "passa la palla". Un esempio del suo utilizzo potrebbe essere se si desidera lanciarlo nei propri metodi privati ​​e gestire invece l'eccezione nel proprio metodo pubblico.

Una buona lettura è il documento Oracle stesso: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Perché i progettisti hanno deciso di forzare un metodo per specificare tutte le eccezioni verificate non rilevate che possono essere generate nel suo ambito? Qualsiasi eccezione che può essere generata da un metodo fa parte dell'interfaccia di programmazione pubblica del metodo. Coloro che chiamano un metodo devono conoscere le eccezioni che un metodo può lanciare in modo da poter decidere cosa fare al riguardo. Queste eccezioni fanno parte dell'interfaccia di programmazione di quel metodo tanto quanto i suoi parametri e valore di ritorno.

La domanda successiva potrebbe essere: "Se è così buono documentare l'API di un metodo, comprese le eccezioni che può generare, perché non specificare anche le eccezioni di runtime?" Le eccezioni di runtime rappresentano problemi che sono il risultato di un problema di programmazione e, come tale, non ci si può ragionevolmente aspettare che il codice client dell'API si ripristini da loro o li gestisca in alcun modo. Tali problemi includono eccezioni aritmetiche, come la divisione per zero; eccezioni del puntatore, come il tentativo di accedere a un oggetto tramite un riferimento null; e eccezioni di indicizzazione, come il tentativo di accedere a un elemento dell'array tramite un indice troppo grande o troppo piccolo.

C'è anche un po 'di informazioni importanti nelle specifiche del linguaggio Java :

Le classi di eccezioni verificate indicate nella clausola dei tiri fanno parte del contratto tra l'implementatore e l'utente del metodo o del costruttore .

La linea di fondo IMHO è che puoi prenderne uno RuntimeException, ma non ti è richiesto e, in effetti, l'implementazione non è richiesta per mantenere le stesse eccezioni non verificate, in quanto non fanno parte del contratto.


Grazie. Un'altra domanda quando fai gorgogliare il exception, dovrei fare il bubble up dell'esatta eccezione o mascherarla usando Exception. Sto scrivendo il codice sopra un po 'di codice legacy ed Exceptionessendo gorgogliato dappertutto. Mi chiedo se questo è il comportamento corretto?
Thang Pham,

1
@Harry Lascerò che le persone con più conoscenza di che ti risponda: stackoverflow.com/questions/409563/...
Aleadam

10

1) No, NumberFormatException è un'eccezione non selezionata. Anche se l'hai preso (non è necessario) perché non è selezionato. Questo perché è una sottoclasse di IllegalArgumentExceptioncui è una sottoclasse di RuntimeException.

2) RuntimeExceptionè la radice di tutte le eccezioni non selezionate. Ogni sottoclasse di RuntimeExceptionè deselezionata. Tutte le altre eccezioni e Throwablevengono verificate ad eccezione degli errori (che sono riportati di seguitoThrowable ).

3/4) Potresti avvisare l'utente che hanno scelto un file inesistente e chiederne uno nuovo. O semplicemente smettere di informare l'utente che hanno inserito qualcosa di non valido.

5) Lancio e cattura 'Exception' è una cattiva pratica. Ma più in generale, potresti generare altre eccezioni in modo che il chiamante possa decidere come gestirlo. Ad esempio, se hai scritto una libreria per gestire la lettura di alcuni input di file e al tuo metodo è stato passato un file inesistente, non hai idea di come gestirlo. Il chiamante vuole chiedere di nuovo o uscire? Quindi restituisci l'eccezione lungo la catena al chiamante.

In molti casi, ciò si unchecked Exceptionverifica perché il programmatore non ha verificato gli input (nel caso della NumberFormatExceptionprima domanda). Ecco perché è facoltativo catturarli, perché esistono modi più eleganti per evitare di generare tali eccezioni.


Grazie. Un'altra domanda quando fai gorgogliare il exception, dovrei fare il bubble up dell'esatta eccezione o mascherarla usando Exception. Sto scrivendo il codice sopra un po 'di codice legacy ed Exceptionessendo gorgogliato dappertutto. Mi chiedo se questo è il comportamento corretto?
Thang Pham,

Puoi anche fare in modo che il tuo metodo generi anche l'eccezione (che non è l'ideale). Oppure prendi l'eccezione e genera un'eccezione migliore (come IOException o qualcosa del genere). Tutte le eccezioni possono prendere un'eccezione nel loro costruttore come 'causa', quindi dovresti usarla.
dontocsata,

8

Controllato: può succedere. Controllato in tempo di compilazione.

Ad esempio FileOperations

Non verificato - Dati errati. Controllato in Tempo di esecuzione.

Per esempio..

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Qui l'eccezione è dovuta a dati errati e in nessun modo può essere determinata durante il tempo di compilazione.


6

Le eccezioni controllate vengono verificate in fase di compilazione dalla JVM e dalle relative risorse (file / db / stream / socket ecc.). Il motivo dell'eccezione controllata è che in fase di compilazione se le risorse non sono disponibili l'applicazione dovrebbe definire un comportamento alternativo per gestirlo nel blocco catch / finally.

Le eccezioni non controllate sono errori puramente programmatici, calcoli errati, dati nulli o persino errori nella logica aziendale possono portare a eccezioni di runtime. È assolutamente corretto gestire / rilevare eccezioni non controllate nel codice.

Spiegazione tratta da http://coder2design.com/java-interview-questions/


5

La mia descrizione preferita in assoluto della differenza tra eccezioni non verificate e verificate è fornita dall'articolo del tutorial Java Tutorial, " Unchecked Exceptions - the Controversy " (mi dispiace di avere tutte le elementari in questo post - ma, ehi, le basi sono a volte le migliori):

Ecco la linea di fondo: se un cliente può ragionevolmente aspettarsi di recuperare da un'eccezione, impostalo come un'eccezione controllata. Se un client non può fare nulla per ripristinare l'eccezione, impostalo come un'eccezione non selezionata

Il cuore di "che tipo di eccezione lanciare" è semantico (in una certa misura) e la citazione precedente fornisce e linee guida eccellenti (quindi, sono ancora spazzato via dall'idea che C # si è sbarazzato delle eccezioni verificate - in particolare come sostiene Liskov per la loro utilità).

Il resto diventa quindi logico: a quali eccezioni il compilatore si aspetta che risponda, esplicitamente? Quelli da cui prevedi il recupero del client.


5

Per rispondere alla domanda finale (gli altri sembrano avere una risposta esaustiva sopra), "Devo creare l'eccezione esatta o mascherarla usando l'eccezione?"

Suppongo che intendi qualcosa del genere:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

No, dichiara sempre l' eccezione più precisa possibile o un elenco di tali. Le eccezioni dichiarate in grado di lanciare il metodo sono parte del contratto tra il metodo e il chiamante. Lanciare "FileNotFoundException"significa che è possibile che il nome del file non sia valido e che il file non verrà trovato; il chiamante dovrà gestirlo in modo intelligente. Lanciare Exceptionsignifica "Ehi, succede. Accordo." È molto scarso API.

Nei commenti sul primo articolo ci sono alcuni esempi in cui "getta Exception" è una dichiarazione valida e ragionevole, ma non è così per la maggior parte del normalcodice " " che scriverai mai.


Esattamente, rendi la tua dichiarazione di eccezione di controllo parte della documentazione del codice e aiuta la persona che utilizza il tuo software.
Salvador Valencia,

5

Eccezioni di runtime : le eccezioni di runtime si riferiscono ad eccezioni non controllate. Tutte le altre eccezioni sono eccezioni controllate e non derivano da java.lang.RuntimeException.

Eccezioni controllate : un'eccezione controllata deve essere rilevata da qualche parte nel codice. Se si richiama un metodo che genera un'eccezione controllata ma non si rileva l'eccezione controllata da qualche parte, il codice non verrà compilato. Ecco perché vengono chiamate eccezioni controllate: il compilatore verifica per essere gestito o dichiarato.

Numerosi metodi nell'API Java generano eccezioni controllate, quindi spesso si scriveranno gestori di eccezioni per far fronte alle eccezioni generate da metodi che non sono stati scritti.


3

Perché fanno esplodere l'eccezione? La gestione dell'errore non è migliore prima? Perché bolle?

Ad esempio, supponiamo che tu abbia un'applicazione client-server e che il client abbia fatto una richiesta per alcune risorse che non è stato possibile trovare o per qualcos'altro errore che potrebbe essersi verificato sul lato server durante l'elaborazione della richiesta dell'utente, quindi è dovere del server per dire al client perché non è riuscito a ottenere ciò che ha richiesto, quindi per farlo sul lato server, il codice è scritto per generare l'eccezione usando la parola chiave lancio invece di ingoiarla o gestirla. esso, quindi non ci sarà alcuna possibilità di intimare al cliente che l'errore si era verificato.

Nota: per fornire una descrizione chiara di ciò che si è verificato il tipo di errore, possiamo creare il nostro oggetto Exception e inviarlo al client.


Buon punto. Ciò significa che si passa al livello più responsabile che controlla il flusso logico e sovrintende alla logica aziendale per l'applicazione. Sarebbe impossibile, ad esempio, per il livello del database comunicare al client che qualcosa di critico manca o non risponde. Quando passa al livello più alto del server, è semplice aggiornare la vista del client con un messaggio di errore critico.
Salvador Valencia,


3

Voglio solo aggiungere qualche ragionamento per non usare affatto le eccezioni verificate. Questa non è una risposta completa, ma ritengo che risponda a una parte della tua domanda e integri molte altre risposte.

Ogni volta che sono coinvolte eccezioni controllate, c'è un punto throws CheckedExceptionnella firma di un metodo ( CheckedExceptionpotrebbe esserci un'eccezione controllata). Una firma NON genera un'eccezione, generare eccezioni è un aspetto dell'implementazione. Interfacce, firme dei metodi, classi principali, tutte queste cose NON dovrebbero dipendere dalle loro implementazioni. L'uso delle eccezioni selezionate qui (in realtà il fatto che devi dichiarare ilthrows firma del metodo) sta vincolando le interfacce di livello superiore con le implementazioni di tali interfacce.

Lascia che ti mostri un esempio.

Facciamo un'interfaccia bella e pulita come questa

public interface IFoo {
    public void foo();
}

Ora possiamo scrivere molte implementazioni del metodo foo(), come queste

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Class Foo è perfettamente bene. Ora facciamo un primo tentativo in classe Bar

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

Questa barra di classe non verrà compilata. Poiché InterruptedException è un'eccezione verificata, è necessario acquisirla (con un metodo try-catch all'interno foo ()) o dichiarare che la si sta lanciando (aggiungendo throws InterruptedExceptionalla firma del metodo). Dato che non voglio catturare questa eccezione qui (voglio che si propaga verso l'alto in modo da poterla gestire correttamente da qualche altra parte), cambiamo la firma.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

Neanche questa barra di classe verrà compilata! Il metodo foo () di Bar NON sovrascrive il metodo foo () di IFoo poiché le loro firme sono diverse. Potrei rimuovere l'annotazione @Override, ma voglio programmare come l'interfaccia IFoo come IFoo foo;e in seguito decidere su quale implementazione voglio usare, come foo = new Bar();. Se il metodo foo di Bar () non sostituisce il metodo fooo di IFoo, quando lo facciofoo.foo(); non chiamerà l'implementazione di bar di foo ().

Per fare in modo che Bar public void foo() throws InterruptedExceptionsostituisca IFoo, DEVO public void foo()aggiungere throws InterruptedExceptionla firma del metodo IFoo. Questo, tuttavia, causerà problemi con la mia classe Foo, poiché la sua firma del metodo foo () differisce dalla firma del metodo IFoo. Inoltre, se aggiungessi throws InterruptedExceptional metodo foo () di Foo, otterrei un altro errore affermando che il metodo foo () di Foo dichiara che genera un InterruptedException ma non genera mai un InterruptedException.

Come puoi vedere (se ho fatto un lavoro decente nello spiegare queste cose), il fatto che sto lanciando un'eccezione controllata come InterruptedException mi sta costringendo a legare la mia interfaccia IFoo a una delle sue implementazioni, che a sua volta provoca il caos su IFoo altre implementazioni!

Questo è un grande motivo per cui le eccezioni controllate sono MALE. In maiuscolo.

Una soluzione è acquisire l'eccezione selezionata, racchiuderla in un'eccezione non selezionata e generare l'eccezione non selezionata.


2
Sì, è male perché hai detto che non volevi prenderlo. Ma per evitare di influire sulla firma dell'IFOO dovrai farlo. Preferirei farlo e andare avanti invece di riequilibrare tutte le firme delle mie interfacce per evitare di rilevare un'eccezione (solo perché le eccezioni sono MALE).
Salvador Valencia,

Sì sono d'accordo. Non ero un po 'chiaro su qualcosa. Voglio propagare un'eccezione, quindi posso affrontarla da qualche altra parte. Una soluzione è intercettare InterruptedException e generare un'eccezione non selezionata. cioè evitiamo le eccezioni verificate e passiamo intorno alle eccezioni non controllate (anche se hanno senso solo come wrapper)
Blueriver

"Questo, tuttavia, causerà problemi con la mia classe Foo, poiché la sua firma del metodo foo () differisce dalla firma del metodo IFoo". Ho appena testato la tua idea ed è possibile compilare anche se aggiungiamo throws InterruptedExceptionalla firma del metodo IFoo senza lanciare nulla in nessuna implementazione. Quindi non causa davvero alcun problema. Se in un'interfaccia si lancia ogni firma del metodo Exception, si dà semplicemente all'implementazione la possibilità di lanciare o meno un'eccezione (qualsiasi eccezione, poiché Exceptionincapsula tutte le eccezioni).
Flyout91,

Tuttavia, ammetto che può essere fonte di confusione perché quando implementerai tale inteface e fai clic su qualcosa come "Aggiungi metodi non implementati", verranno automaticamente creati con la throw Exceptionclausola nella loro firma, anche se l'implementazione non genererà nulla o potrebbe essere un'eccezione più specifica. Ma mi sento ancora come una buona pratica lanciare sempre l'eccezione per il metodo di un'interfaccia perché, ancora una volta, offre all'utente la possibilità di lanciare o non lanciare nulla.
Flyout91,

Questo manca l'intero punto. Lo scopo di un'interfaccia è dichiarare soddisfatto il contratto che un cliente richiede. Ciò può includere scenari di errore che è in grado di gestire. Quando un'implementazione rileva un errore, deve mappare tale errore sull'errore astratto appropriato dichiarato dall'interfaccia client.
Erickson,

3
  • Java distingue tra due categorie di eccezioni (selezionata e non selezionata).
  • Java impone una cattura o un requisito dichiarato per le eccezioni verificate.
  • Il tipo di un'eccezione determina se un'eccezione è selezionata o deselezionata.
  • Tutti i tipi di eccezione diretti o indiretti subclassesdella classe RuntimeException sono eccezioni non selezionate.
  • Tutte le classi che ereditano dalla classe Exceptionma non RuntimeExceptionsono considerate checked exceptions.
  • Le classi ereditate dalla classe Errore sono considerate deselezionate.
  • Il compilatore controlla ogni chiamata e decelerazione del metodo per determinare se il metodo viene generato checked exception.
    • In tal caso, il compilatore garantisce che l'eccezione venga rilevata o dichiarata in una clausola di lancio.
  • Per soddisfare la parte dichiarata del requisito catch-or-declare, il metodo che genera l'eccezione deve fornire una throwsclausola contenente il file checked-exception.
  • Exception le classi sono definite per essere verificate quando sono considerate abbastanza importanti da catturare o dichiarare.

2

Ecco una semplice regola che può aiutarti a decidere. È correlato al modo in cui le interfacce vengono utilizzate in Java.

Prendi la tua classe e immagina di progettare un'interfaccia per essa tale che l'interfaccia descriva la funzionalità della classe ma nessuna delle implementazioni sottostanti (come dovrebbe fare un'interfaccia). Fai finta che potresti implementare la classe in un altro modo.

Guarda i metodi dell'interfaccia e considera le eccezioni che potrebbero generare:

Se un'eccezione può essere generata da un metodo, indipendentemente dall'implementazione sottostante (in altre parole, descrive solo la funzionalità), probabilmente dovrebbe essere un'eccezione controllata nell'interfaccia.

Se l'implementazione sottostante provoca un'eccezione, non dovrebbe trovarsi nell'interfaccia. Pertanto, deve essere un'eccezione non selezionata nella classe (poiché le eccezioni non selezionate non devono apparire nella firma dell'interfaccia), oppure è necessario racchiuderla e ricominciare come un'eccezione verificata che fa parte del metodo dell'interfaccia.

Per decidere se eseguire il wrapping e il rilancio, è necessario considerare nuovamente se sia logico che un utente dell'interfaccia debba gestire immediatamente la condizione di eccezione o se l'eccezione è così generale che non è possibile fare nulla al riguardo e dovrebbe propagare lo stack. L'eccezione racchiusa ha senso se espressa come funzionalità della nuova interfaccia che si sta definendo o è solo un vettore per un sacco di possibili condizioni di errore che potrebbero verificarsi anche con altri metodi? Se il primo, potrebbe essere comunque un'eccezione controllata, altrimenti dovrebbe essere deselezionato.

Di solito non dovresti pianificare eccezioni "bubble-up" (cattura e ripeti). O un'eccezione dovrebbe essere gestita dal chiamante (nel qual caso è selezionata) o dovrebbe arrivare fino a un gestore di alto livello (nel qual caso è più semplice se non è selezionata).


2

Solo per sottolineare che se si genera un'eccezione controllata in un codice e la cattura è di pochi livelli sopra, è necessario dichiarare l'eccezione nella firma di ciascun metodo tra l'utente e la cattura. Pertanto, l'incapsulamento viene interrotto perché tutte le funzioni nel percorso di lancio devono conoscere i dettagli di tale eccezione.


2

In breve, le eccezioni che il tuo modulo o moduli sopra dovrebbero gestire durante il runtime sono chiamate eccezioni controllate; altre sono eccezioni non selezionate che sono RuntimeExceptiono Error.

In questo video, vengono spiegate le eccezioni verificate e non verificate in Java:
https://www.youtube.com/watch?v=ue2pOqLaArw


1

Tutte queste sono eccezioni controllate. Le eccezioni non selezionate sono sottoclassi di RuntimeException. La decisione non è come gestirli, è il codice che dovrebbe lanciarli. Se non vuoi che il compilatore ti dica che non hai gestito un'eccezione, allora usi un'eccezione non selezionata (sottoclasse di RuntimeException). Dovrebbero essere salvati per situazioni da cui non è possibile recuperare, come errori di memoria insufficiente e simili.


um. se NumberFormatException è un'eccezione controllata, come dici tu, non è in contraddizione con il fatto che è ereditata da RuntimeException ?
eis,

Scusa, non ero molto chiaro. Mi riferivo a FileNotFoundException e non a NumberFormatException. Basato sul suo # 2 e # 4, sembrava che pensasse che Checked vs. Unchecked fosse basato su come hai gestito l'eccezione dopo averla catturata. Non come è stato definito.
Mamboking il

-1

Se qualcuno si preoccupa dell'ennesima prova per non gradire le eccezioni verificate, consulta i primi paragrafi della popolare libreria JSON:

"Sebbene si tratti di un'eccezione verificata, è raramente recuperabile. La maggior parte dei chiamanti dovrebbe semplicemente racchiudere questa eccezione in un'eccezione non selezionata e ricodificare:"

Quindi, perché nel mondo qualcuno dovrebbe far continuare gli sviluppatori a controllare l'eccezione, se invece dovessimo "semplicemente avvolgerla"? lol

http://developer.android.com/reference/org/json/JSONException.html


4
Perché è solo la maggior parte dei chiamanti, non tutti i chiamanti, che dovrebbe avvolgere e ricominciare. Il fatto che l'eccezione sia selezionata significa che il chiamante deve pensare se sono uno dei "più" chiamanti o una delle minoranze che può e deve gestire l'eccezione.
Warren Dew,

1
Se ti piace controllare gli errori per ogni chiamata che fai, "torna" a C. Le eccezioni sono un modo per separare la normale esecuzione del programma da anomala, senza inquinare il tuo codice. Le eccezioni assicurano che non è possibile ignorare un errore silenziosamente a un certo livello .
Slawomir,

-1

Eccezioni controllate :

  • Le eccezioni che vengono verificate dal compilatore per l'esecuzione regolare del programma in fase di esecuzione sono denominate Checked Exception.

  • Questi si verificano in fase di compilazione.

  • Se questi non vengono gestiti correttamente, daranno un errore di tempo di compilazione (non eccezione).
  • Tutte le sottoclassi della classe Exception tranne RuntimeException sono Checked Exception.

    Esempio ipotetico - Supponiamo che tu stia lasciando la tua casa per l'esame, ma se controlli se hai preso il tuo biglietto Hall a casa (tempo di compilazione), allora non ci saranno problemi all'Exam Hall (runtime).

Eccezione non selezionata :

  • Le eccezioni che non vengono verificate dal compilatore sono denominate Eccezioni non selezionate.

  • Questi si verificano in fase di esecuzione.

  • Se queste eccezioni non vengono gestite correttamente, non generano errori durante la compilazione. Ma il programma verrà terminato prematuramente in fase di esecuzione.

  • Tutte le sottoclassi di RunTimeException ed Error sono eccezioni non selezionate.

    Esempio ipotetico - Supponiamo che tu sia nella tua sala d'esame, ma in qualche modo la tua scuola ha avuto un incidente di fuoco (mezzi in fase di esecuzione) in cui non puoi fare nulla in quel momento, ma le precauzioni possono essere prese prima (tempo di compilazione).


-2

Tutte le eccezioni devono essere verificate eccezioni.

  1. Le eccezioni non controllate sono goto illimitate. E i goto senza restrizioni sono considerati una cosa negativa.

  2. Le eccezioni non selezionate interrompono l'incapsulamento. Per elaborarli correttamente, è necessario conoscere tutte le funzioni nella struttura delle chiamate tra il lanciatore e il ricevitore per evitare bug.

  3. Le eccezioni sono errori nella funzione che li genera ma non errori nella funzione che li elabora. Lo scopo delle eccezioni è di dare una seconda possibilità al programma rinviando la decisione se si tratta di un errore o meno in un altro contesto. È solo nell'altro contesto che può essere presa la decisione corretta.

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.