Was ist Ausnahmeverkettung in Java? Ausnahmebehandlung
Was verstehen Sie unter verketteten Ausnahmen in Java?
Ausnahmeverkettung oder Ausnahmeumbruch ist eine objektorientierte Programmiertechnik zur Behandlung von Ausnahmen . Eine Ausnahmeverkettung erfolgt, wenn eine Ausnahme eine andere Ausnahme verursacht. Eine verkettete Ausnahme ist eine Ausnahme, die durch eine andere Ausnahme verursacht wird. Verkettete Ausnahmen sind so verknüpft, dass die vorherige Ausnahme jede Ausnahme in der Kette verursacht.
· Auslösbare Klasse
· Verwendung verketteter Ausnahmen
· Warum verkettete Ausnahmen?
· Schwierigkeiten mit verketteten Ausnahmen
· Programm
Wurfbare Klasse
Konstruktoren der Throwable-Klasse, die verkettete Ausnahmen in Java unterstützen:
- Throwable(Throwable Cause) :- Wobei Cause die Ausnahme ist, die die aktuelle Ausnahme verursacht.
- Throwable(String msg, Throwable Cause) :- Wobei msg die Ausnahmemeldung und Cause die Ausnahme ist, die die aktuelle Ausnahme verursacht.
- getCause()- Methode: – Diese Methode gibt die tatsächliche Ursache einer Ausnahme zurück.
- initCause-Methode (auslösbare Ursache) : – Diese Methode legt die Ursache für die aufrufende Ausnahme fest.
Oft möchten Sie eine Ausnahme abfangen und eine andere auslösen, aber dennoch die Informationen über die ursprüngliche Ausnahme behalten – dies wird als Ausnahmeverkettung bezeichnet. Die ursprüngliche Ausnahme ist die Ursache der zweiten Ausnahme. Verkettete Ausnahmen ermöglichen es also, eine Ausnahme mit einer anderen Ausnahme in Beziehung zu setzen, dh eine Ausnahme beschreibt die Ursache einer anderen Ausnahme.
Vor JDK 1.4 mussten Programmierer ihren eigenen Code schreiben, um die ursprünglichen Ausnahmeinformationen beizubehalten, aber jetzt haben alle Throwable-Unterklassen die Option, ein Cause-Objekt in ihren Konstruktor zu übernehmen. Die Ursache soll die ursprüngliche Ausnahme sein, und durch ihre Übergabe behalten Sie den Stack-Trace bis zu seinem Ursprung bei, auch wenn Sie eine neue Ausnahme erstellen und auslösen.
Die Ausnahmeverkettung wird auch als Ausnahmeumbruch bezeichnet , da wir dies tun, indem wir eine abgefangene Ausnahme erneut auslösen, nachdem wir sie in eine neue Ausnahme eingeschlossen haben. Die ursprüngliche Ausnahme wird als Eigenschaft (z. B. Ursache ) der neuen Ausnahme gespeichert.
Üben
try {
// creating an exception
NullPointerException e = new NullPointerException("Actual cause");
// wrapping the original exception in a new exception
ArithmeticException exc = new ArithmeticException("Apearent cause",e);
// throwing the exception
throw exc;
} catch(ArithmeticException e) {
// display top level exception (aprearent cause)
System.out.println("Caught: " + e);
// Getting the actual cause of the exception
System.out.println("Original cause: " + e.getCause());
}
}
Caught: java.lang.ArithmeticException: Apearent cause
Original cause: java.lang.NullPointerException: Actual cause
Stellen Sie sich beispielsweise eine Methode vor, die aufgrund eines Versuchs, durch Null zu dividieren, eine ArithmeticException auslöst, die eigentliche Ursache der Ausnahme jedoch ein E/A-Fehler war , der dazu führte, dass der Divisor Null war. Die Methode wirft die ArithmeticException an den Aufrufer. Der Aufrufer wüsste nichts über die eigentliche Ursache einer Exception . In solchen Situationen wird eine verkettete Ausnahme verwendet.
Es ist interessant festzustellen, dass die einzigen Throwable-Unterklassen, die das Ursachenargument im Konstruktor bereitstellen, die drei grundlegenden Ausnahmeklassen Error (von der JVM zum Melden von Systemfehlern verwendet), Exception und RuntimeException sind . Wenn Sie andere Ausnahmetypen verketten möchten, tun Sie dies über die initCause( ) -Methode und nicht über den Konstruktor.
Beispiel
Hier ist ein Beispiel, das die Mechanismen der Behandlung verketteter Ausnahmen veranschaulicht:
// Demonstrate exception chaining.
class ChainExcDemo {
static void demoproc() {
// create an exception
NullPointerException e = new NullPointerException("top layer");
// add a cause
e.initCause(new ArithmeticException("cause"));
throw e;
}
public static void main(String args[]) {
try {
demoproc();
} catch (NullPointerException e) {
// display top level exception
System.out.println("Caught: " + e);
// display cause exception
System.out.println("Original cause: " + e.getCause());
}
}
}
Caught: java.lang.NullPointerException: top layer
Original cause: java.lang.ArithmeticException: cause
Verkettete Ausnahmen können in der erforderlichen Tiefe ausgeführt werden. Somit kann die Ursachenausnahme selbst eine Ursache haben. Beachten Sie, dass zu lange Ausnahmeketten auf ein schlechtes Design hinweisen können.
Verkettete Ausnahmen werden nicht von jedem Programm benötigt. In Fällen, in denen die Kenntnis einer zugrunde liegenden Ursache jedoch nützlich ist, bieten sie eine elegante Lösung.
Warum verkettete Ausnahmen?
Durch die Ausnahmeverkettung können Sie einen Ausnahmetyp einem anderen zuordnen, sodass eine Methode Ausnahmen auslösen kann, die auf derselben Abstraktionsebene wie die Methode selbst definiert sind, ohne wichtige Debuginformationen zu verwerfen.
Das heißt, wenn Sie über eine Methode verfügen, die ein Objekt aus einer Datenbank lädt, möchten Sie möglicherweise lieber eine ResourceLoadException (die eher mit der Abstraktionsebene der Methode zusammenhängt) als eine SQLException auf niedriger Ebene , selbst wenn dies die ursprüngliche Ursache des Problems war. Wenn Sie jedoch einfach die SQLException abfangen und stattdessen eine ResourceLoadException auslösen , gehen möglicherweise wichtige Debuginformationen verloren.
Daher ist die Verkettung der Ausnahmen eine gute Alternative. Sie lösen eine „High-Level“-Ausnahme aus, die für die jeweilige Methode gut geeignet ist, verketten sie jedoch mit der Ausnahme, die sie verursacht hat.
Wir müssen die Ausnahmen verketten, um Protokolle lesbar zu machen. Schreiben wir zwei Beispiele. Erstens ohne Verkettung der Ausnahmen und zweitens mit verketteten Ausnahmen. Später werden wir vergleichen, wie sich Protokolle in beiden Fällen verhalten.
Zunächst erstellen wir eine Reihe von Ausnahmen:
class NoLeaveGrantedException extends Exception {
public NoLeaveGrantedException(String message, Throwable cause) {
super(message, cause);
}
public NoLeaveGrantedException(String message) {
super(message);
}
}
class TeamLeadUpsetException extends Exception {
// Both Constructors
}
Schreiben wir ein Beispielprogramm, ohne unsere benutzerdefinierten Ausnahmen zu verketten.
public class MainClass {
public void main(String[] args) throws Exception {
getLeave();
}
void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
e.printStackTrace();
throw new NoLeaveGrantedException("Leave not sanctioned.");
}
}
void howIsTeamLead() throws TeamLeadUpsetException {
throw new TeamLeadUpsetException("Team Lead Upset");
}
}
com.baeldung.chainedexception.exceptions.TeamLeadUpsetException:
Team lead Upset
at com.baeldung.chainedexception.exceptions.MainClass
.howIsTeamLead(MainClass.java:46)
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:34)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Exception in thread "main" com.baeldung.chainedexception.exceptions.
NoLeaveGrantedException: Leave not sanctioned.
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:37)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Als nächstes schreiben wir ein Beispiel mit der Verkettung unserer benutzerdefinierten Ausnahmen:
public class MainClass {
public void main(String[] args) throws Exception {
getLeave();
}
public getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
throw new NoLeaveGrantedException("Leave not sanctioned.", e);
}
}
public void howIsTeamLead() throws TeamLeadUpsetException {
throw new TeamLeadUpsetException("Team lead Upset.");
}
}
Exception in thread "main" com.baeldung.chainedexception.exceptions
.NoLeaveGrantedException: Leave not sanctioned.
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:36)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Caused by: com.baeldung.chainedexception.exceptions
.TeamLeadUpsetException: Team lead Upset.
at com.baeldung.chainedexception.exceptions.MainClass
.howIsTeamLead(MainClass.java:44)
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:34)
... 1 more
Schwierigkeiten mit verketteten Ausnahmen
Wir können die Ausnahmeverkettung in Situationen verwenden, in denen eine andere Ausnahme eine Ausnahme verursacht. Es ist jedoch wichtig zu beachten, dass die Verkettung die Lesbarkeit und das Verständnis unseres Codes erschweren kann. Daher sollten wir die Ausnahmeverkettung sparsam und nur bei Bedarf einsetzen.
Wenn wir verkettete Ausnahmen verwenden, ist es eine gute Idee, die Kette in unserem Code zu dokumentieren. Es hilft anderen, unseren Code zu verstehen und erleichtert das Debuggen, wenn ein Fehler auftritt.
Programm
//: exceptions/DynamicFields.java
// A Class that dynamically adds fields to itself.
// Demonstrates exception chaining.
import static net.mindview.util.Print.*;
class DynamicFieldsException extends Exception {}
public class DynamicFields {
private Object[][] fields;
public DynamicFields(int initialSize) {
fields = new Object[initialSize][2];
for(int i = 0; i < initialSize; i++)
fields[i] = new Object[] { null, null };
}
public String toString() {
StringBuilder result = new StringBuilder();
for(Object[] obj : fields) {
result.append(obj[0]);
result.append(": ");
result.append(obj[1]);
result.append("\n");
}
return result.toString();
}
//...................hasField(String id)........................//
private int hasField(String id) {
for(int i = 0; i < fields.length; i++)
if(id.equals(fields[i][0]))
return i;
return -1;
}
//......................getFieldNumber(String id)....................//
private int getFieldNumber(String id) throws NoSuchFieldException {
int fieldNum = hasField(id);
if(fieldNum == -1)
throw new NoSuchFieldException();
return fieldNum;
}
//........................makeField(String id).....................//
private int makeField(String id) {
for(int i = 0; i < fields.length; i++)
if(fields[i][0] == null) {
fields[i][0] = id;
return i;
}
// No empty fields. Add one:
Object[][] tmp = new Object[fields.length + 1][2];
for(int i = 0; i < fields.length; i++)
tmp[i] = fields[i];
for(int i = fields.length; i < tmp.length; i++)
tmp[i] = new Object[] { null, null };
fields = tmp;
// Recursive call with expanded fields:
return makeField(id);
}
//.............................getField(String id).......................//
public Object getField(String id) throws NoSuchFieldException {
return fields[getFieldNumber(id)][1];
}
//.........................setField(String id, Object value)..........................
public Object setField(String id, Object value) throws DynamicFieldsException {
if(value == null) {
// Most exceptions don’t have a "cause" constructor.
// In these cases you must use initCause(),
// available in all Throwable subclasses.
DynamicFieldsException dfe = new DynamicFieldsException();
dfe.initCause(new NullPointerException());
throw dfe;
}
int fieldNumber = hasField(id);
if(fieldNumber == -1)
fieldNumber = makeField(id);
Object result = null;
try {
result = getField(id); // Get old value
} catch(NoSuchFieldException e) {
// Use constructor that takes "cause":
throw new RuntimeException(e);
}
fields[fieldNumber][1] = value;
return result;
}
// ......................main...................//
public static void main(String[] args) {
DynamicFields df = new DynamicFields(3);
print(df);
try {
df.setField("d", "A value for d");
df.setField("number", 47);
df.setField("number2", 48);
print(df);
df.setField("d", "A new value for d");
df.setField("number3", 11);
print("df: " + df);
print("df.getField(\"d\") : " + df.getField("d"));
Object field = df.setField("d", null); // Exception
} catch(NoSuchFieldException e) {
e.printStackTrace(System.out);
} catch(DynamicFieldsException e) {
e.printStackTrace(System.out);
}
}
}
null: null
null: null
null: null
d: A value for d
number: 47
number2: 48
df: d: A new value for d
number: 47
number2: 48
number3: 11
df.getField("d") : A new value for d
DynamicFieldsException
at DynamicFields.setField(DynamicFields.java:64)
at DynamicFields.main(DynamicFields.java:94)
Caused by: java.lang.NullPointerException
at DynamicFields.setField(DynamicFields.java:66)
... 1 more
*///:~
Als Rückgabewert ruft setField() mit getField() auch den alten Wert an dieser Feldposition ab , was eine NoSuchFieldException auslösen könnte . Wenn der Client-Programmierer getField( ) aufruft , ist er für die Behandlung von NoSuchFieldException verantwortlich. Wenn diese Ausnahme jedoch in setField( ) ausgelöst wird , handelt es sich um einen Programmierfehler, sodass die NoSuchFieldException mithilfe des Konstruktors, der ein Ursachenargument akzeptiert, in eine RuntimeException konvertiert wird.
Sie werden feststellen, dass toString( ) einen StringBuilder verwendet , um sein Ergebnis zu erstellen. Mehr über StringBuilder erfahren Sie im Kapitel „Strings“, aber im Allgemeinen möchten Sie es immer dann verwenden, wenn Sie einen toString( ) schreiben , der eine Schleife beinhaltet, wie es hier der Fall ist.
Viel Spaß beim Lernen
Treten Sie der Mouad Oumous Java WhatsApp-Gruppe bei
Treten Sie dem Telegram-Kanal von Mouad Oumous bei
Unterstützen Sie unsere Publikation, indem Sie ihr folgen
Maximieren Sie das Potenzial Ihres Teams: So halten Sie Ihr Software-Delivery-Team beschäftigt. Am häufigsten gestellte Java8-Stream-basierte Interviewfrage – letzter Teil. So erstellen Sie ein einfaches Quarkus-Projekt mit Datenbankintegration. Erneutes Auslösen einer Ausnahme in Java | Ausnahmebehandlung: Ich verdiene 300 US-Dollar, indem ich in zwei Tagen ein Buch schreibe – hier erfahren Sie, wie Sie mit 10 einfachen, aber effektiven Möglichkeiten Ihre Lebensqualität verbessern können
![Was ist überhaupt eine verknüpfte Liste? [Teil 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































