2015-08-07 13 views
6

Desidero gestire le eccezioni di due tipi diversi in modo diverso e successivamente effettuare alcune azioni identiche per entrambi i tipi di eccezione. Come farlo in Java?Azioni specifiche e identiche quando si verificano più eccezioni

Il seguente codice mostra cosa voglio fare, ma non è corretto, poiché un'eccezione non può essere rilevata due volte.

Qual è la sintassi corretta per questo?

try { 
    // do something... 
} 
catch (ExceptionA e) { 
    // actions for ExceptionA 
} 
catch (ExceptionB e) { 
    // actions for ExceptionB 
} 
catch (ExceptionA | ExceptionB e) { 
    // actions for ExceptionA & ExceptionB 
} 
+0

creare una classe eccezione personalizzata. – ravi

+1

È possibile inserire il codice nelle funzioni e richiamare le funzioni nel blocco catch. – Jens

+0

@Jens Questa non è una soluzione, questo è semplicemente lo scaricamento del problema da qualche altra parte ... – insidesin

risposta

4

Utilizzare il costrutto catch (ExceptionA | ExceptionB e). All'interno del blocco catch, eseguire prima un controllo instanceof per e e gestire separatamente i tipi di eccezione. Dopo questo, avere la gestione comune per entrambi i tipi. In questo modo si può fare tutto in un unico blocco catch:

try { 
    // do something... 
} catch (ExceptionA | ExceptionB e) { 
    if (e instanceof ExceptionA) { 
     // handling for ExceptionA 
    } else { 
     // handling for ExceptionB 
    } 
    // common handling for both exception types 
} 
+0

Oppure puoi nidificare due blocchi di cattura uno che gestisce i due separatamente l'altro che gestisce il pezzo comune. l'ordine dipenderà se la cosa che vuoi fare in una o l'altra dipende l'una dall'altra :). – Rob

+0

@Mick Mnemonic Ho usato la soluzione, poiché è la più facilmente leggibile e chiara. –

1

Se siete in cerca di (ExceptionA | ExceptionB) si sarà in grado di catturare sia e gestire in modo identico, sarà richiesto un solo a fallire. Questo è essenzialmente solo nuovo (1.7) abbreviazione per più condizioni Exception.

Non esiste una cosa come catch(ExceptionA && ExceptionB).

Ad esempio:

readFile { 
    try { 
     open the file; 
     determine its size; 
     determine its content; 
    } catch (fileOpenFailed) { 
     doSomething; 
    } catch (sizeDeterminationFailed) { 
     doSomething; 
    } catch (contentDeterminationFailed) { 
     doSomething; 
    } 
} 

Se si voleva catturare contentDeterminationFailed e sizeDeterminationFailed come il singolo exception allora si vorrebbe creare il proprio personalizzato exception tipo che può essere gestito in modo univoco.

1

utilizzare un metodo per il codice comune.

try { 
    // do something... 
} 
catch (ExceptionA e) { 
    // actions for ExceptionA 
    doCommon(parameters); 
} 
catch (ExceptionB e) { 
    // actions for ExceptionA 
    doCommon(parameters); 
} 

..... 

void doCommon(parameters) { 
    // actions for ExceptionA & ExceptionB 
} 

Questo funzionerà per la maggior parte delle cose.
Anche se ci sono alcune eccezioni come return. Per questo si può avere doCommon ritorno castrato il chiamante deve restituire o meno e usarlo come:

catch (ExceptionA e) { 
    // actions for ExceptionA 
    if (doCommon(parameters)) 
     return; 
} 
catch (ExceptionB e) { 
    // actions for ExceptionA 
    if (doCommon(parameters)) 
     return; 
} 

Una soluzione "nativo Java" non esiste. JLS specifica (sottolineatura mia):

14.20.1. Esecuzione di try-catch

Un'istruzione try senza un blocco finally viene eseguita eseguendo prima il blocco di prova . Poi c'è una scelta:

Se l'esecuzione del blocco try viene completata normalmente, non viene eseguita alcuna ulteriore azione e l'istruzione try viene completata normalmente.

Se l'esecuzione del blocco try completa bruscamente a causa di un lancio di un valore V, allora v'è una scelta:

Se il tipo di runtime di V è compatibile con assegnazione (§5.2) un classe di eccezione catchable di qualsiasi clausola catch dell'istruzione try, quindi la prima clausola catch (a sinistra) è selezionata.Il valore V viene assegnato al parametro della clausola catch selezionato, e viene eseguito il blocco di tale clausola catch, e quindi v'è una scelta:

Se quel blocco completa normalmente, allora l'istruzione try completa normalmente .

Se quel blocco si completa bruscamente per qualsiasi motivo, la prova viene completata improvvisamente per lo stesso motivo.

Se il tipo di runtime di V non è compatibile con l'assegnazione di una classe di catturabile eccezione di qualsiasi clausola catch dell'istruzione try, allora l'istruzione try completa bruscamente a causa di un lancio del V. valore

Quindi viene eseguito solo il primo blocco di catch che si applica. Non c'è modo di eseguire due blocchi catch per la stessa istruzione try.

+0

L'estrazione del metodo è, ovviamente, una soluzione. Ma mi interessa se esiste un costrutto try/catch nativo per questo. –

+1

No, non esiste un tale costrutto. Ho aggiornato la mia risposta con la parte pertinente del JLS. –

0

È possibile rigenerare l'eccezione e gestirlo ancora:

try { 
    try { 
     // do something 
    } catch(ExceptionA e) { 
     // actions for ExceptionA 
     throw e; 
    } catch(ExceptionB e) { 
     // actions for ExceptionB 
     throw e; 
    } 
} catch(ExceptionA | ExceptionB e) { 
    // Actions for exceptions A or B 
} 

Forse, per motivi di chiarezza, si potrebbe refactoring in metodi. Sto assumendo che le eccezioni siano controllate eccezioni.

private void doSomethingHelper() throws ExceptionA, ExceptionB { 
    try { 
     // do something 
    } catch(ExceptionA e) { 
     // actions for ExceptionA 
     throw e; 
    } catch(ExceptionB e) { 
     // actions for ExceptionB 
     throw e; 
    } 
} 

public void doSomething() { 
    try { 
     doSomethingHelper(); 
    } catch(ExceptionA | ExceptionB e) { 
     // Actions for exceptions A or B 
    } 
} 
+0

Questo non fa altro che complicare la situazione ... L'ultima presa risolve il problema da sola. – insidesin

+0

@insidesin Non sono d'accordo, si tratta di un blocco di prova annidato. Il fermo interno può gestire singolarmente l'eccezione A o B, mentre quella esterna può essere gestita in generale per entrambi gli interni. – dave

+0

Quindi lo stai gestendo due volte per quale motivo? Se proprio ne hai bisogno, fai un 'instanceof' .. – insidesin

1

Sarebbe una soluzione di questo tipo di lavoro per voi:

try { 
// do something... 
} catch (ExceptionA | ExceptionB e) { 
    // common code to be called for both... 
    // .... 
    handleException(e) 
} 

//.... 
void handleException(ExceptionA e) { 
    // code for A 
} 
//.... 
void handleException(ExceptionB e) { 
    // code for B 
} 

In questo modo un primo momento si fanno le azioni comuni per i due problemi, poi si ha il codice comune per ciascuna delle eccezioni il metodo appropriato. In questo modo non è necessario utilizzare l'istanza di o ifs.

Un altro modo di farlo solo utilizzando costrutti Java è mettendo nel infine così:

boolean fail = false; 

try { 
    // your code 
} catch (ExceptionA a) { 
    // exceptionA specific handling 
    fail = true; 
} catch (ExceptionB b) { 
    // exceptionB specific handling 
    fail = true; 
} finally { 
    if (fail) { 
     // common handling 
    } 
} 
+0

Soluzioni carine! –

+0

Hai provato tu stesso la soluzione migliore? Questo non funziona per me, perché il compilatore non può risolvere il metodo 'handleException (ExceptionA | ExceptionB)'. Dovresti cambiare la firma in 'handleException (Exception e)' che sconfigge lo scopo ... – r0estir0bbe