2010-02-04 11 views
17

Ich habe eine Funktion, die eine Schleife ausführt, während ich etwas mache, das eine Ausnahme auslösen könnte. Sieht in etwa so aus:Eine verknüpfte Liste von Ausnahmen in Java werfen

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

Der Fehler, der die Ausnahme verursacht, ist wiederherstellbar. Es kann sich um einen SQL-Fehler in einer einzelnen update-Anweisung handeln, bei der die while-Schleife eine Reihe von update-Anweisungen ausführt. Oder ein Parsing-Fehler in einem einzelnen Datenstück, bei dem die Schleife mehrere Datenstücke verarbeitet. Ich muss die Ausnahme weiter oben in der Kette weiterleiten, damit der GUI-Teil des Programms es verarbeiten, verarbeiten und den Fehler an den Benutzer weitergeben kann. Aber ich möchte die Schleife in dieser speziellen Funktion nicht töten. Die anderen Dinge, die es tut, sind möglicherweise nicht ungültig. Der Fehler, der die Ausnahme verursacht hat, ist möglicherweise für die Funktion nicht tödlich.

Also meine Frage ist das: Ist es eine akzeptable Praxis, verknüpfte Listen von benutzerdefinierten Ausnahmen zu erstellen (wo jede Ausnahme ein Knoten ist, und die Ausnahme ist der Kopf der Liste geworfen) und dann den Kopf der Liste zu werfen (falls vorhanden) sobald die Schleife beendet ist?

Hat jemand das schon mal gesehen? Kann jemand an mögliche Probleme denken? Kann jemand an andere, bessere Möglichkeiten denken, mit dem Grundproblem umzugehen: die Notwendigkeit, mehrere nicht verwandte Ausnahmen zu verwerfen, ohne die Funktion zu verlassen, bis sie erledigt ist?

Hier ist ein Beispiel dafür, wie die Verknüpfung und werfen könnten sehr einfach realisiert werden:

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

Durch die Art und Weise. Darüber hinaus verwenden Sie eine verknüpfte Liste hier oder nicht. Es gibt eine Klasse 'java.util.LinkedList', die sofort verwendet werden kann, so dass Sie ihre Funktionen nicht in Ihren Objekt-Objekten programmieren müssen (in diesem Fall' MyException'). – helios

+0

Ich bin mir dessen bewusst. Ich dachte nicht, dass du es in diesem Fall benutzen könntest, weil die Liste geworfen werden muss und LinkedList nicht umwerfbar ist. –

Antwort

16

Mein intial Gedanken (anders als ich dies habe nicht zu sehen) ist, dass eine Ausnahme ist möglicherweise ein sehr großes Objekt (mit dem Stacktrace) und ich würde nicht bevorzugen, um eine Menge von ihnen zu speichern.

Ich würde stattdessen eine Liste der fehlerhaften Parameter/Argumente als Ausnahmen erstellen, und nach Abschluss der Schleife, eine benutzerdefinierte Ausnahme mit dieser Liste gefüllt (wenn die Liste mehr als 0 Elemente). Dies scheint eine handhabbarere Art dieses Szenario zu handhaben.

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

Die vorhandene Funktionssignatur gibt void zurück. Sie könnten einfach die Liste der fehlgeschlagenen Objekte oder eine andere Struktur, die Erfolg und Misserfolg sammelt, usw. – TREE

+0

@TREE Ich bin ziemlich sicher, dass ein Beispiel ist, nicht die tatsächliche Methode – Kevin

+0

+1, das ist besser als meine. Ich habe Ihren Code repariert, um '' CustomException '' zu deklarieren. Achte darauf, dass 'Error' eine vorhandene Klasse in' java.lang' ist. Sie möchten vielleicht den Namen ändern, um Verwirrung zu vermeiden. – BalusC

3

Müssen Sie wirklich alle Ausnahmen werfen? Wie erwarten Sie, dass die einzelnen, nicht miteinander verbundenen Ausnahmen behandelt werden? Im Allgemeinen wird das System in solchen Fällen nur die Fehler melden und damit erledigt sein.

Wenn ja, möchten Sie vielleicht nur die Fehlermeldungen sammeln und sie zu einer benutzerdefinierten Exception Klasse hinzufügen und das werfen.

1

Wenn die durch DoSomething(); ausgelöste Ausnahme dazu führen könnte, dass dieselbe Methode eine weitere Ausnahme auslöst; Dies könnte ein Problem sein. Mit anderen Worten, wenn DoSomething(); eine Exception auslöst, weil Sie nicht mit der vorherigen behandelt haben, könnte ein unnötiger Fehler auftreten.

+0

Wahr. In dem Szenario, nach dem ich frage, wäre das (theoretisch) nicht der Fall, aber das ist definitiv etwas, das man im Kopf behalten sollte. –

3

Wenn diese Ausnahmen wirklich nicht miteinander verwandt sind, so dass Sie keinen Nutzen aus get/setCause() ziehen können, würde ich lieber diese Informationen in einem MyException sammeln.

z.

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; 
    } 
} 

Update:Brian behandelt genau diesen Ansatz in einer sauberen Art und Weise.Ich würde stattdessen dafür entscheiden :)

0

IMO, sollte eine Ausnahme die letzte Ressource sein, die Sie für die Behandlung eines Fehlers haben. Es sollte vermieden werden, wenn möglich. Vielleicht möchten Sie also die Fehlerbeschreibung (Fehlercodes erstellen, die Nachricht weitergeben oder etwas Sinnvolles) an die GUI und nicht die Ausnahme selbst senden.

2

Das Auslösen von Ausnahmen von einer solchen Funktion ist wahrscheinlich nicht die richtige Methode, wenn Fehler auftreten. Ich würde vorschlagen, entweder eine Liste (Array) aller aufgetretenen Ausnahmen/Fehler zurückzugeben oder besser ein Fehlerbehandlungsobjekt für die Funktion bereitzustellen, die mit den Ausnahmen umgehen kann. dh:

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); 
     } 
    } 
} 

Auf diese Weise kann auch die Fehlerbehandlung entweder die Fehler sammeln sie den Benutzer zu präsentieren oder zu entscheiden, dass der gesamte Batch-Betrieb ungültig aufgrund eines Fehlers worden ist und eine Ausnahme von seinem eigenen werfen abbrechen die Verarbeitung früh.

+0

Ich sehe diesen Ansatz ist besser als @Brain Agnew Antwort aus den folgenden Gründen 1.Error Handler bietet Ihnen verschiedene Ausnahmen anders behandeln, wenn nötig 2. Keine weitere Erstellung von Array von Fehlern (oder eine Art von Indikatoren) als Sie behandeln Fehler, wie sie passieren. – Stackee007

1

Ich denke, dass Sie einige Callback oder Listener an die Methode übergeben können, oder in einer Variablen der Klasse und statt eines Wurfs die Liste, wie x4u tat.

In Java gibt es eine Schnittstelle für diese bereits: java.beans.ExceptionListener