Frage

Ich möchte eine Ausnahme machen, die in eine andere Ausnahme verschachtelt ist. Ich mache es derzeit so:

} catch (RemoteAccessException e) {
    if (e != null && e.getCause() != null && e.getCause().getCause() != null) {
        MyException etrp = (MyException) e.getCause().getCause();
        ...
    } else {
        throw new IllegalStateException("Error at calling service 'service'");
    }
}

Gibt es eine Möglichkeit, dies effizienter und eleganter zu machen?

War es hilfreich?

Lösung

Es gibt keine elegante Art, verschachtelte Ausnahmen selektiv zu "fangen". Ich nehme an, wenn Sie diese Art von verschachtelten Ausnahme viel fangen, könnten Sie den Code möglicherweise in eine gemeinsame Versorgungsmethode umwandeln. Aber es wird immer noch weder elegant noch effizient sein.

Die elegante Lösung besteht darin, mit Ausnahmebernstörungen zu beseitigen. Entweder ketten Sie die Ausnahmen nicht überhaupt nicht oder (selektiv) und die verschachtelten Ausnahmen weiter oben im Stapel ausschalten.

Ausnahmen sind aus 3 Gründen tendenziell verschachtelt:

  1. Sie haben entschieden, dass die Details der ursprünglichen Ausnahme wahrscheinlich nicht für die Fehlerwiederherstellung der Anwendung nützlich sind ... aber Sie möchten sie für diagnostische Zwecke bewahren.

  2. Sie implementieren API unvermeidlich wirft diese Ausnahme aus. Eine übliche Problemumgehung besteht darin, die geprüfte Ausnahme in einer ungeprüften Ausnahme zu "schmuggeln".

  3. Du bist faul und drehst a vielfältig Set nicht verwandte Ausnahmen in eine einzige Ausnahme, um zu vermeiden1.

Wenn Sie im ersten Fall die verpackten Ausnahmen diskriminieren müssen, waren Ihre anfänglichen Annahmen falsch. Die beste Lösung sind Änderungsmethodensignaturen, damit Sie die Verschachtung beseitigen können.

Im zweiten Fall sollten Sie wahrscheinlich die Ausnahmen auspacken, sobald die Kontrolle die problematische API -Methode überschritten hat.

Im dritten Fall sollten Sie Ihre Ausnahmebehandlungsstrategie überdenken. dh es richtig machen2.


1-In der Tat ist einer der semi-legitimen Gründe dafür aufgrund der Einführung der Multi-Exception-Catch-Syntax in Java 7 verschwunden.

2 - Ändern Sie Ihre API -Methoden nicht auf throws Exception. Das macht die Dinge nur noch schlimmer. Sie müssen jetzt entweder "Handle" oder propagieren Exception Jedes Mal, wenn Sie die Methoden anrufen. Es ist ein Krebs ...

Andere Tipps

Das ExceptionUtils#getrootcause () Die Methode kann in solchen Situationen sehr praktisch sein.

Sie sollten einige Schecks hinzufügen, um festzustellen, ob e.getCause().getCause() ist wirklich ein MyException. Andernfalls werfen dieser Code a ClassCastException. Ich würde das wahrscheinlich schreiben wie:

} catch(RemoteAccessException e) {
    if(e.getCause() != null && e.getCause().getCause() instanceof MyException) {
        MyException ex = (MyException)e.getCause().getCause();
        // Do further useful stuff
    } else {
        throw new IllegalStateException("...");
    }
}

Ich habe gerade ein solches Problem gelöst, indem ich eine einfache Versorgungsmethode geschrieben habe, die die gesamte Kette von der Verursachung überprüft.

  /**
   * Recursive method to determine whether an Exception passed is, or has a cause, that is a
   * subclass or implementation of the Throwable provided.
   *
   * @param caught          The Throwable to check
   * @param isOfOrCausedBy  The Throwable Class to look for
   * @return  true if 'caught' is of type 'isOfOrCausedBy' or has a cause that this applies to.
   */
  private boolean isCausedBy(Throwable caught, Class<? extends Throwable> isOfOrCausedBy) {
    if (caught == null) return false;
    else if (isOfOrCausedBy.isAssignableFrom(caught.getClass())) return true;
    else return isCausedBy(caught.getCause(), isOfOrCausedBy);
  }

Wenn Sie es verwenden, erstellen Sie nur eine Liste von IFs aus der spezifischsten Ausnahme bis zum wenigsten spezifisch, mit einem Rückfall, sonst: Klausel:

try {
  // Code to be executed
} catch (Exception e) {
  if (isCausedBy(e, MyException.class)) {
    // Handle MyException.class
  } else if (isCausedBy(e, AnotherException.class)) {
    // Handle AnotherException.class
  } else {
    throw new IllegalStateException("Error at calling service 'service'");
  }
}

Ich sehe keinen Grund, warum Sie eine Ausnahmehandhabung effizient und elegant haben möchten. Sie werden aus einem bestimmten Grund Ausnahmen genannt.

Dieser Code wird ein Wartungsalptraum sein. Kannst du den Anrufstack nicht neu gestalten, um die Ausnahme auszulösen, an der du interessiert bist? Wenn es wichtig ist, sollten die Methodensignaturen sie anzeigen und nicht in zwei anderen Ausnahmen verbergen.

Das erste (e! = Null) ist unnötig.

Und Sie können den dritten besser in e.getCause () ändern.

Sie können wie unten tun:

catch (RemoteAccessException e) {
    int index = ExceptionUtils.indexOfThrowable(e, MyExcetption.class)
    if (index != -1) {
         //handleMyException
    } else {
    }
}

Ich bezweifle, aber Sie können sich wenden instanceof Wenn die Ausnahme vom richtigen Typ ist.

Bearbeiten: Es sollte einen Grund geben, warum die verschachtelte Ausnahme eingewickelt ist. Sie müssen sich also fragen, was der Zweck ist, das verschachtelte zu fangen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top