Frage von 11thSense, 36

Fehlerbehandlung in JAVA: Try/Catch und Throw?

Hallo zusammen,

ich möchte zu diesem Thema in der Schule eine schriftliche Arbeit ausführen, welche anschließend auch benotet wird. Jedoch fällt mir leider schwer, dieses Thema zu verstehen. Diversen Websites und YouTube-Videos konnten mir auch nicht weiterhelfen. Kann mir jemand das einigermaßen gut erklären oder womöglich auf eine gute Website hinweisen die dies gut veranschaulich bzw. erklärt?
Wäre super nett und wäre für jede Hilfe Dankbar!

Vielen Dank im Vorraus :-)

Hilfreichste Antwort - ausgezeichnet vom Fragesteller
von sarahj, 34

Also, fange mal bei Adam & Eva an:

Funktionsaufrufe:

Nehmen wir mal an, Du hast eine Funktion, die eine andere aufruft, und danach noch weitern Code zum Ausführen hat. Z.B.:
f() {
  g();
  h();
}
(also f ruft zuerst g() auf, dann h() )
Wenn die CPU an der Stelle ist, wo g aufzurufen ist, merkt sie sich, wo danach weiter zu machen ist (also die Stelle in f, wo dann h aufgerufen wird). Konkret wird die sogenannte "Rücksprungadresse" gemerkt (und zwar in JAVA auf einem sog. Stack, aber das ist jetzt erst mal egal).

Natürlich kann g dann wieder was aufrufen (also kommt die Rücksprungadresse innerhalb von g wieder auf den Stack), usw.
Die ganze Kette von Aufrufen nennt man "Aufrufkette". Und  (in JAVA) steht die dann auf dem Stack.

Der Stack (auch Stapel) ist ein Speicherbereich, auf dem man was ablegen, und in umgekehrter Reihenfolge wieder auslesen kann (Last-in, First out).
So liegt immer die letzte Rücksprungadresse "oben" auf dem Stack.
Am Ende einer Funktion holt die CPU die letzte Rücksprungadresse, und macht da weiter. Damit kann man verschachtelte Funktionsaufrufe machen.

Soweit so gut.

Jetzt nimm mal an, tief unten, in einem verschachtelten Funktionsaufruf passiert ein Fehler. Z.B. division durch 0 oder Datei nicht gefunden usw.
Das nennt man "Exception" (also Ausnahme oder auch Ausnahmefehler).

Dann macht das JAVA Programm folgendes: es sucht rückwärts entlang der Aufrufkette nach einer Funktion, die einen sogenannten Exceptionhandler (also eine Behandlungsroutine) für diese Exception bereitstellt.
Wenn gefunden, wird die ganze Aufrufkette bis dahin abgeräumt (vergessen), und direkt in der Behandlungsroutine weiter gemacht. Es werden also alle dazwischen liegenden Funktionsaufrufe sofort beendet.
Eine solche Behandlungsroutine definierst Du mit try-catch.
Das Konstrukt:
try {
   g();
} catch(Exception e) {
  ...handlercode..
}
bewirkt also folgendes:
 wenn innerhalb des try-blocks (also hier: in g) ein Fehler passiert, dann werden alle Aufrufe die bis dagin gemacht wurden abgeräumt, und sofort im handlercode weiter gemacht.
Der Fehler kann dabei beliebig tief unten (also nicht nur in g selbst, sondern auch einer darin aufgerufenen Funktion passieren).

Soweit so gut. Wie löst man nun eine solche Exception aus?

Das macht der throw(exception) Aufruf. D.h. wenn irgendwo tief unten throw() aufgerufen wird, passiert obiges.

Da man sich eigene Exceptions definieren kann, kann man damit von tief unten aus einer aufgerufenen Funktion heraus, Fehler melden.
Die meisten exception-handler zeigen dann z.B ein Dialogfenster ("Interner Fehler, bla bla konnte leider nicht gemacht werden") und führen das Programm mehr oder weniger korrekt weiter.
Ohne exception-handler (also wenn beim throw kein handler gefunden wird), wird typischerweise das programm beendet.

(das war ein bisschen vereinfachend, und gilt auch nur für Java und C++; andere Programmiersprachen erlauben noch flexiblere Fehlerbehandlung)

Kommentar von 11thSense ,

Ok danke, das hab ich jetzt sogar bis auf wenige Kleinigkeiten relativ gut verstehen können!! Jedoch wirft sich mir jetzt immer noch die Frage auf, weshalb ich Throw verwende, und was diese bewirkt. Soweit ich weiß "schmeißt" Throw die Exception doch einfach weiter? Das ist doch keine richtige Fehlerbehandlung dann oder?😄

Kommentar von sarahj ,

nein, throw wirft die Exception. Der handler wird gesucht, und der code dann ausgeführt. Im handler kann man natürlich wieder throwen... dann wird ein weiterer handler gesucht, wenn man das will. (nennt man rethrow)

Bei division durch 0 macht die CPU selbst den throw.
Bei file-not-found die file-open-methode in einer file-Klasse.
ein readerrorexception z.B. der code in einer stream klasse.
usw.

Kommentar von sarahj ,

ungefähr so (ist jetzt kein Java, aber ähnlich):


f() {
  System.out.println("f1\n");
  try {
    System.out.println("f2\n");
    g();
    System.out.println("f3\n");
  } catch(Exception ex) {
    System.out.println("handler\n");
  }
  System.out.println("f4\n");
}

g() {
  System.out.println("g1\n");
  h();
  System.out.println("g2\n");
}

h() {
  System.out.println("h1\n");
  throw(Exception);
  System.out.println("h2\n");
}


die Ausgabe ist dann:
f1
f2
g1
h1
handler
f4


klar?
Statt "Exception" kannst Du auch jede andere Exception-Klasse nehmen, oder eine eigene definieren.
Wichtig ist noch, daß der handler zur exception passen muss.
Wenn nicht, wird in der Aufrufkette weiter gesucht.

Kommentar von sarahj ,

Danke für den * (anscheinend lief die Arbeit ganz gut ;-)

Antwort
von Omnivore08, 31

Schon in der Javadoc geschaut?

https://docs.oracle.com/javase/tutorial/essential/exceptions/try.html

Kommentar von 11thSense ,

Englisch ist jetzt nicht soooo toll, wenn ich schon Probleme mit dem Thema hab.. Aber danke Dir! :-)

Keine passende Antwort gefunden?

Fragen Sie die Community