Kann ich mehrere Java-Ausnahmen in derselben catch-Klausel abfangen?

699

In Java möchte ich so etwas tun:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}

...anstatt:

try {
    ...     
} catch (IllegalArgumentException e) {
    someCode();
} catch (SecurityException e) {
    someCode();
} catch (IllegalAccessException e) {
    someCode();
} catch (NoSuchFieldException e) {
    someCode();
}

Gibt es eine Möglichkeit, dies zu tun?

froadie
quelle

Antworten:

1131

Dies ist seit Java 7 möglich . Die Syntax für einen Multi-Catch-Block lautet:

try { 
  ...
} catch (IOException | SQLException ex) { 
  ...
}

Denken Sie jedoch daran, dass Sie einfach diesen Basisausnahmetyp abfangen können, wenn alle Ausnahmen zur selben Klassenhierarchie gehören.

Beachten Sie auch, dass Sie ExceptionA und ExceptionB nicht im selben Block abfangen können, wenn ExceptionB direkt oder indirekt von ExceptionA geerbt wird. Der Compiler wird sich beschweren:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA
OscarRyz
quelle
81
TT - warum den Operator bitwise or( |) neu definieren ? Warum nicht ein Komma oder den Operator verwenden, der eine ähnlichere Bedeutung hat, das logical or( ||)?
ArtOfWarfare
11
@ArtOfWarfare Vielleicht dachten sie, es würde keine Rolle mehr spielen, nachdem sie bereits die Syntax für mehrere Grenzen für Generika entwickelt hatten.
JimmyB
12
Das XOR-Zeichen (I) ist nicht dasselbe wie OR (||), A | B bedeutet entweder A oder B, aber nicht beide A || B bedeutet entweder A oder B oder beides, so dass es für Ausnahmen entweder Ausnahme A oder Ausnahme B ist, aber nicht beide gleichzeitig. Aus diesem Grund haben sie XOR sing anstelle von OR verwendet, und Sie können deutlich sehen, dass beim
Auslösen
41
@ user1512999 in Java ist bitweises XOR ^ (caret) und bitweises ODER ist | (Pipe) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Lewis Baumstark
6
Es ist erwähnenswert, dass der Typ einer Ausnahme, die im Multi-Catch-Block abgefangen wird, für den am häufigsten abgeleiteten gemeinsamen Elternteil
ausgewertet wird
104

Nicht genau vor Java 7, aber ich würde so etwas tun:

Java 6 und früher

try {
  //.....
} catch (Exception exc) {
  if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
     exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) {

     someCode();

  } else if (exc instanceof RuntimeException) {
     throw (RuntimeException) exc;     

  } else {
    throw new RuntimeException(exc);
  }

}



Java 7

try {
  //.....
} catch ( IllegalArgumentException | SecurityException |
         IllegalAccessException |NoSuchFieldException exc) {
  someCode();
}
user454322
quelle
11
Beachten Sie, dass Ihr Java 6-Beispiel die Fähigkeit des Compilers beeinträchtigt, zu bestimmen, was von wo geworfen wird.
MichaelBlume
2
@ MichaelBlume True, was nicht [so] schlecht ist. Sie können immer die ursprüngliche Ausnahme mit erhalten exc.getCause(). Als Randnotiz empfiehlt Robert C. Martin (unter anderem), ungeprüfte Ausnahmen zu verwenden (der Compiler hat keine Ahnung, welche Art von Ausnahme von dort ausgelöst wird). Siehe Kapitel 7: Fehlerbehandlung in seinem Buch Code reinigen .
user454322
4
Sollten Sie in Ihrem Java 6-Beispiel nicht die ursprüngliche Ausnahme erneut auslösen, anstatt eine neue Ausnahmeinstanz zu erstellen, dh throw excanstelle von throw new RuntimeException(exc)?
David DeMar
5
Dies ist aus Sicht der Lesbarkeit eine ziemlich schlechte Praxis.
Rajesh J Advani
3
Die Instanz des Betriebs ist etwas kostspielig, es ist besser, so viel wie möglich zu vermeiden.
Paramesh Korrakuti
23

In Java 7 können Sie mehrere catch-Klauseln definieren, z.

catch (IllegalArgumentException | SecurityException e)
{
    ...
}
Crusam
quelle
16

Wenn es eine Hierarchie von Ausnahmen gibt, können Sie die Basisklasse verwenden, um alle Unterklassen von Ausnahmen abzufangen. Im entarteten Fall können Sie alle Java-Ausnahmen abfangen mit:

try {
   ...
} catch (Exception e) {
   someCode();
}

In einem häufigeren Fall, wenn RepositoryException die Basisklasse und PathNotFoundException eine abgeleitete Klasse ist, gilt Folgendes:

try {
   ...
} catch (RepositoryException re) {
   someCode();
} catch (Exception e) {
   someCode();
}

Der obige Code fängt RepositoryException und PathNotFoundException für eine Art der Ausnahmebehandlung ab, und alle anderen Ausnahmen werden zusammengefasst. Seit Java 7 gemäß der obigen Antwort von @ OscarRyz:

try { 
  ...
} catch( IOException | SQLException ex ) { 
  ...
}
Michael Shopsin
quelle
7
Übrigens werden catch-Klauseln in der richtigen Reihenfolge behandelt. Wenn Sie also eine übergeordnete Ausnahmeklasse vor eine untergeordnete Klasse stellen, wird diese niemals aufgerufen, z. B.: Try {...} catch (Exception e) {someCode (); } catch (RepositoryException re) {// nie erreicht}
Michael Shopsin
4
Genau deshalb, weil es niemals erreichbar ist, wird ein solcher Code nicht einmal kompiliert.
Polygenelubricants
15

Nein, eine pro Kunde.

Sie können eine Oberklasse wie java.lang.Exception abfangen, solange Sie in allen Fällen dieselbe Aktion ausführen.

try {
    // some code
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception
    e.printStackTrace();
}

Dies ist jedoch möglicherweise nicht die beste Vorgehensweise. Sie sollten eine Ausnahme nur dann abfangen, wenn Sie eine Strategie für die tatsächliche Behandlung haben - und Protokollieren und erneutes Werfen bedeutet nicht "Behandeln". Wenn Sie keine Korrekturmaßnahme haben, fügen Sie diese besser der Methodensignatur hinzu und lassen Sie sie an jemanden weitergeben, der mit der Situation umgehen kann.

Duffymo
quelle
20
Kann ich Sie bitten, den Teil über das Abfangen von java.lang.Exception neu zu formulieren? Mir ist klar, dass dies ein Beispiel ist, aber ich habe das Gefühl, dass einige Leute diese Antwort lesen und sagen: "Oh, okay, dann fange ich einfach eine Ausnahme", wenn sie das wahrscheinlich nicht wollen (oder sollten).
Rob Hruska
2
Ich wusste davon, aber ich will es nicht tun ... Oh, nun, ich denke, ich stecke dann mit 4 Fängen fest, bis zur nächsten Version von Java ...
froadie
@duffymo: Was ist falsch am Protokollieren und erneuten Werfen? Abgesehen davon, dass es den Code überfüllt, was bedeutet, ihn nicht zu fangen, nicht wahr? Aus der Perspektive der allgemeinen Fehlerbehandlungsstrategie gesehen. Was schlecht ist, ist protokollieren und nicht neu werfen.
Frank Osterfeld
5
Ich denke nicht daran, irgendetwas zu protokollieren und neu zu werfen. Ich würde es lieber jemandem überlassen, der etwas Sinnvolles tun kann. Die letzte Ebene, auf der Ausnahmen niemals auftreten sollten (z. B. Controller in einer Web-App), sollte in diesem Fall diejenige sein, die den Fehler protokolliert.
Duffymo
Bin ich der einzige, der es absurd findet, dass ein Protokoll nicht automatisch für mich generiert wird? Es scheint, dass wir alle jedes Mal dieselbe dumme Protokollierungsnachricht schreiben müssen, wenn ein Code eine Ausnahme auslöst.
ArtOfWarfare
10

Eine sauberere (aber weniger ausführliche und möglicherweise nicht bevorzugte) Alternative zur Antwort von user454322 auf Java 6 (dh Android) wäre, alle Exceptions zu fangen und s erneut zu werfen RuntimeException. Dies würde nicht funktionieren, wenn Sie planen, andere Arten von Ausnahmen weiter oben im Stapel abzufangen (es sei denn, Sie werfen sie auch erneut), sondern alle effektiv abgefangen Ausnahmen .

Zum Beispiel:

try {
    // CODE THAT THROWS EXCEPTION
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        // this exception was not expected, so re-throw it
        throw e;
    } else {
        // YOUR CODE FOR ALL CHECKED EXCEPTIONS
    } 
}

Aus Gründen der Ausführlichkeit ist es jedoch möglicherweise am besten, einen Booleschen Wert oder eine andere Variable festzulegen und basierend darauf nach dem try-catch-Block Code auszuführen.

Oleg Vaskevich
quelle
1
Dieser Ansatz verhindert, dass der Compiler bestimmt, ob ein "catch-Block" erreichbar ist oder nicht.
the_new_mr
3

In Pre-7 wie wäre es mit:

  Boolean   caught = true;
  Exception e;
  try {
     ...
     caught = false;
  } catch (TransformerException te) {
     e = te;
  } catch (SocketException se) {
     e = se;
  } catch (IOException ie) {
     e = ie;
  }
  if (caught) {
     someCode(); // You can reference Exception e here.
  }
Bill S.
quelle
3
wuold eine schöne Lösung sein. Wie wäre es, die letzte Kontrolle von caughtin einen finallyBlock einzufügen ?
Andrea_86
Dies erfordert mehr Zeilen als die ursprüngliche Frage.
Leandro Glossman
1

Ja. Hier ist der Weg mit dem Rohrabscheider (|):

try
{
    .......
}    
catch
{
    catch(IllegalArgumentException | SecurityException | IllegalAccessException | NoSuchFieldException e)
}
Shiva
quelle
Was ist dieser Codestil? Der catch-Block in einen try-Block?
Sam
1

Für Kotlin ist es momentan nicht möglich, aber sie haben darüber nachgedacht, es hinzuzufügen: Quelle
Aber im Moment nur ein kleiner Trick:

try {
    // code
} catch(ex:Exception) {
    when(ex) {
        is SomeException,
        is AnotherException -> {
            // handle
        }
        else -> throw ex
    }
}
Dr.jacky
quelle
0

Fangen Sie die Ausnahme ab, die zufällig eine übergeordnete Klasse in der Ausnahmehierarchie ist. Dies ist natürlich eine schlechte Praxis . In Ihrem Fall ist die allgemeine übergeordnete Ausnahme zufällig die Exception-Klasse, und das Abfangen einer Ausnahme, die eine Instanz von Exception ist, ist in der Tat eine schlechte Praxis. Ausnahmen wie NullPointerException sind normalerweise Programmierfehler und sollten normalerweise durch Überprüfen auf Nullwerte behoben werden.

Vineet Reynolds
quelle