2010-02-04 1 views
17

Ho una funzione che si interrompe mentre si fa qualcosa che potrebbe generare un'eccezione. Assomiglia a questo:Lancio di un elenco collegato di eccezioni in Java

public void myFunction() throws MyException { 
    while(stuff) { 
     try { 
      DoSomething() // throws an exception 
     } 
     catch (Exception ex) { 
      throw new MyException(some, stuff, of, mine, ex); 
     } 
    } 
} 

L'errore che causa l'eccezione è recuperabile. Può essere qualcosa di simile a un errore SQL in una singola istruzione di aggiornamento in cui il ciclo while esegue una serie di istruzioni di aggiornamento. O un errore di analisi in un singolo pezzo di dati, in cui il loop sta elaborando più pezzi di dati. Devo passare l'eccezione più in alto sulla catena in modo che la parte GUI del programma possa elaborarla, gestirla e trasmettere l'errore all'utente. Ma non voglio uccidere il ciclo in questa particolare funzione. Le altre cose che sta facendo potrebbero non essere non valide. L'errore che ha causato l'eccezione potrebbe non essere fatale per la funzione.

Quindi la mia domanda è questa: È una pratica accettabile creare elenchi collegati di eccezioni personalizzate (dove ogni eccezione è un nodo e l'eccezione generata è il capo dell'elenco) e quindi lanciare il capo dell'elenco (se c'è) una volta che il ciclo finisce?

Qualcuno l'ha mai visto? Qualcuno può pensare a potenziali problemi con questo? Qualcuno può pensare ad altri, modi migliori per gestire il problema di root: la necessità di passare più eccezioni non correlate senza uscire dalla funzione fino a quando non viene eseguita?

Ecco un esempio di come il collegamento e un tiro potrebbero essere attuate in modo molto semplice:

public void myFunction() throws MyException { 
    MyException head = null; 
    while(stuff) { 
     try { 
      DoSomething() // throws an exception 
     } 
     catch (Exception ex) { 
      MyException tmp = new MyException(some, stuff, of, mine, ex); 
      tmp.next(head); 
      head = tmp; 
     } 
    } 
    if(head != null) 
     throw head; 
} 
+2

proposito. Oltre a te usi una lista collegata qui o no. C'è una classe 'java.util.LinkedList' pronta per l'uso, quindi non devi programmare il suo funzionamento all'interno degli oggetti oggetto (in questo caso,' MyException'). – helios

+0

Ne sono consapevole. Non pensavo che potessi usarlo in questo caso, perché la lista deve essere lanciata e LinkedList non è un throwable. –

risposta

16

Il mio pensiero intial (diverso da quello che non ho visto questo) è che un'eccezione è potenzialmente abbastanza un oggetto di grandi dimensioni (contenente lo stacktrace) e preferirei non per memorizzarne molti.

Vorrei invece creare un elenco di parametri/argomenti errati come si verificano eccezioni, e al termine del ciclo, lanciare un'eccezione personalizzata popolata con questo elenco (se l'elenco contiene più di 0 elementi). Sembrerebbe un modo più maneggevole di gestire questo scenario.

public void myFunction() throws CustomException { 
    List<MyError> errors = new ArrayList<MyError>(); 
    while(stuff) { 
     try { 
      DoSomething() // throws an exception 
     } 
     catch (Exception ex) { 
      errors.add(new MyError(some, stuff, of, mine, ex)); 
     } 
    } 
    if (errors.size() > 0) { 
     throw new CustomException(errors); 
    } 
} 
+0

La firma della funzione esistente restituisce void. Potresti semplicemente restituire l'elenco degli oggetti non riusciti, o qualche altra struttura che raccoglie successi e insuccessi, ecc. – TREE

+0

@TREE Sono abbastanza certo che sia un esempio, non il metodo effettivo – Kevin

+0

+1, questo è più ordinato del mio. Ho corretto il tuo codice per dichiarare 'getta CustomException'. Oh, tieni presente che 'Errore' è una classe esistente in' java.lang'. Ti piacerebbe forse cambiare il nome per evitare confusione. – BalusC

3

Hai davvero bisogno di lanciare tutte le eccezioni? Come ti aspetti che vengano gestite le eccezioni individuali e non correlate? Generalmente in casi come questo, il sistema segnalerà solo gli errori e sarà fatto con esso.

In tal caso, è possibile raccogliere solo i messaggi di errore e aggiungerli a una classe personalizzata Exception e lanciarli.

1

Se l'eccezione generata da DoSomething(); potrebbe causare lo stesso metodo per generare un'altra eccezione; questo potrebbe essere un problema. In altre parole, se DoSomething(); genera un'eccezione perché non hai gestito il precedente, potrebbe esserci un errore non necessario da gestire.

+0

Vero. Nello scenario che sto chiedendo di questo non sarebbe (teoricamente) il caso, tuttavia, questo è sicuramente qualcosa da tenere a mente. –

3

Se tali eccezioni non sono realmente correlate l'una all'altra in modo che non sia possibile usufruire di get/setCause(), quindi preferisco raccogliere queste informazioni in uno MyException.

E.g.

public void myFunction() throws MyException { 
    MyException myException = null; 
    while(stuff) { 
     try { 
      DoSomething() // throws an exception 
     } 
     catch (Exception ex) { 
      if (myException == null) { 
       myException = new MyException(); 
      } 
      myException.addException(some, stuff, of, mine, ex); 
     } 
    } 
    if (myException != null) { 
     throw myException; 
    } 
} 

Aggiornamento:Brian gestisce esattamente questo approccio in modo più accurato.Io invece opterei per questo :)

0

IMO, un'eccezione dovrebbe essere l'ultima risorsa disponibile per gestire un errore. Dovrebbe essere evitato se possibile. Quindi, potresti voler passare la descrizione dell'errore (creare codici di errore, passare il messaggio o qualcosa di significativo) alla GUI e non l'eccezione stessa.

2

In realtà il lancio di eccezioni da una funzione di questo tipo non è probabilmente il modo giusto per gestirlo se ci si aspetta che ci siano errori. Suggerirei di restituire una lista (matrice) di tutte le eccezioni/errori verificatisi o meglio fornire un oggetto gestore di errori alla funzione che può gestire le eccezioni. vale a dire:

public interface ErrorHandler 
{ 
    public void handleError(Throwable ex /*, add some context info */); 
} 

public void myFunction(ErrorHandler eh) 
{ 
    while(stuff) { 
     try { 
      DoSomething() // throws an exception 
     } 
     catch (Exception ex) { 
      if(eh != null) 
       eh.handleError(ex); 
     } 
    } 
} 

In questo modo anche il gestore degli errori o raccogliere gli errori di presentarli all'utente o di decidere che l'intera operazione di travaso è diventato nullo a causa di qualche errore e per gettare un eccezione di essa la propria abortire l'elaborazione anticipata.

+0

Vedo che questo approccio è migliore della risposta @Brain Agnew per i seguenti motivi 1. Il gestore degli errori fornisce diverse eccezioni in caso di necessità 2. Non c'è più costruzione di array di errori (o una sorta di indicatori) come tali errori mentre accadono. – Stackee007

1

Penso che si possa passare qualche callback o listener al metodo, o impostare in una variabile di classe e invece di lanciare la lista, come x4u ha fatto.

In Java esiste un'interfaccia per questo già: java.beans.ExceptionListener