Exceptions
Kurz gesagt: Eine Exception ist ein Objekt, das einen Fehler beschreibt, der während des Programmlaufs passiert ist: Der Stacktrace zeigt, wo, und try und catch fangen ihn, damit das Programm weiterlaufen kann.
Problem
12a statt 12
Die Konzertkasse fragt, wie viele Tickets du willst. Ein Ticket kostet 15 €.
class Program{ static void Main() { Console.Write("Wie viele Tickets? "); int tickets = int.Parse(Console.ReadLine()); Console.WriteLine("Gesamt: " + tickets * 15 + " €"); }}Mit der Eingabe 12 sagt das Programm „Gesamt: 180 €“. Aber der Kunde hat es eilig und tippt einen Buchstaben zu viel:
Wie viele Tickets? 12aUnhandled exception. System.FormatException: The input string '12a' was not in a correct format. at System.Number.ThrowFormatException[TChar](ReadOnlySpan`1 value) at System.Int32.Parse(String s) at Program.Main() in /projects/Tickets/Program.cs:line 6Das Programm hält an. Statt der Summe kommt ein langer Text, und die Zeile „Gesamt“ wird nie erreicht. Was bedeutet dieser Text, und wie verhinderst du, dass das Programm wegen eines Buchstabens anhält?
Die Idee
Exception
int.Parse muss eine Zahl zurückgeben. Aus „12a“ kann es keine Zahl machen, und irgendeine Zahl zurückzugeben wäre gelogen. Deshalb erzeugt die Methode ein Objekt, das das Problem beschreibt, und wirft es. Dieses Objekt heißt Exception (Ausnahme).
Wenn niemand sie fängt, hält das Programm an und zeigt, was passiert ist. Dieser Text heißt Stacktrace, und du liest ihn von oben nach unten:
- Die erste Zeile: die Art der Exception und die Meldung.
FormatException: The input string '12a' was not in a correct format.: Die Zahl hat das falsche Format, und hier ist der Text. - Die Zeilen mit „at“: wo es passiert ist. Das ist der Aufrufstapel aus der Lektion über Rekursion, von innen nach außen. Ganz oben ist die Methode, die die Exception geworfen hat, und ganz unten ist
Main. - Deine Zeile: die erste „at“-Zeile, die auf deine Datei zeigt. Hier:
Program.cs:line 6. Die Zeilen darüber sind im Code von .NET, und du brauchst sie selten.
Die Meldungen sind auf Englisch, weil die Sprache sie schreibt, nicht du.
Probier es aus
Finde den Fehler
Das Programm soll das letzte Ergebnis aus der Klassenarbeit ausgeben. Es hält damit an:
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array. at Program.LastScore(Int32[] scores) in /projects/Tickets/Program.cs:line 5 at Program.Main() in /projects/Tickets/Program.cs:line 11Lies den Stacktrace. In welcher Zeile des Programms steckt der Fehler?
Wähle die Zeile mit dem Fehler.
LastScore, Zeile 5. Die Zeile darunter ist Main, Zeile 11: Von dort wurde die Methode aufgerufen, aber der Fehler ist nicht dort. Die erste Zeile sagt auch, was es ist: Index 5 bei Länge 5. Der letzte Index ist scores.Length - 1.Die Idee
try und catch
Eine Exception kann man fangen. Der Code, der werfen könnte, kommt in try („versuche“). Was bei einem Fehler passieren soll, schreibst du in catch („fange“):
Console.Write("Wie viele Tickets? ");try{ int tickets = int.Parse(Console.ReadLine()); Console.WriteLine("Gesamt: " + tickets * 15 + " €");}catch (FormatException){ Console.WriteLine("Das ist keine ganze Zahl.");}Console.WriteLine("Vielen Dank!");12aWie viele Tickets? Das ist keine ganze Zahl.Vielen Dank!- In die Klammern von
catchschreibst du, welche Art von Exception du fängst. - Wenn im
tryalles gut geht, wirdcatchübersprungen. Mit der Eingabe12ist die Ausgabe „Gesamt: 180 €“ und „Vielen Dank!“. - Nach
catchmacht das Programm weiter. Es hält nicht mehr an.
Console.Write("Wie viele Tickets? ");try{ int tickets = int.Parse(Console.ReadLine()); Console.WriteLine("Gesamt: " + tickets * 15 + " €");}catch (FormatException){ Console.WriteLine("Das ist keine ganze Zahl.");}Console.WriteLine("Vielen Dank!");Schritt für Schritt, in Worten
- Das Programm fragt, wie viele Tickets. Du tippst „12a“.
- Im try: int.Parse versucht, aus „12a“ eine Zahl zu machen.
- Das geht nicht. Die Methode wirft FormatException.
- Die Ausführung springt direkt in catch. Die Zeile mit „Gesamt“ wird übersprungen.
- catch ist für genau diese Art von Fehler da: Es gibt die Meldung für den Kunden aus.
- Nach catch macht das Programm weiter. Es hält nicht an.
Genauer, für Neugierige
- Eine Variable, die im
trydeklariert wird (hiertickets), existiert nur bis zur schließenden Klammer destry. Wenn du sie auch nach dem Block brauchst, deklariere sie vor demtry.
- In C# kannst du die Exception ohne Namen lassen:
catch (FormatException). Das machst du, wenn du sie nicht brauchst. Wenn du einen Namen schreibst und ihn nicht benutzt, gibt der Compiler eine Warnung.
Probier es aus
Welche Zeilen laufen?
Was gibt das Programm aus?
Console.WriteLine("Start");try{ Console.WriteLine("Ich lese"); int seats = int.Parse("zehn"); Console.WriteLine("Gelesen: " + seats);}catch (FormatException){ Console.WriteLine("Falsche Eingabe");}Console.WriteLine("Ende");„Ich lese“ wird ausgegeben, weil es vor dem Fehler steht. Dann wirft Parse, und die Ausführung springt direkt in catch. „Gelesen“ wird übersprungen. Nach catch macht das Programm mit „Ende“ weiter.
Die Idee
Was in der Exception steht
Die Exception ist ein Objekt, und e in catch (FormatException e) ist die Variable, die darauf zeigt. Das Objekt kann dir die Meldung geben: e.Message.
try{ int tickets = int.Parse(Console.ReadLine()); Console.WriteLine("Gesamt: " + tickets * 15 + " €");}catch (FormatException e){ Console.WriteLine("Fehler: " + e.Message);}12aFehler: The input string '12a' was not in a correct format.Die Meldung ist nützlich für dich, wenn du den Fehler suchst. Dem Kunden zeigst du meistens deinen eigenen Text in seiner Sprache, etwa „Das ist keine ganze Zahl.“
Die Idee
Frag, bis es stimmt
Der Kunde hat sich vertippt. Du musst nicht anhalten. Frag noch einmal:
int tickets;while (true){ Console.Write("Wie viele Tickets? "); try { tickets = int.Parse(Console.ReadLine()); break; } catch (FormatException) { Console.WriteLine("Gib eine ganze Zahl ein, zum Beispiel 3."); }}Console.WriteLine("Gesamt: " + tickets * 15 + " €");12azwölf12Wie viele Tickets? Gib eine ganze Zahl ein, zum Beispiel 3.Wie viele Tickets? Gib eine ganze Zahl ein, zum Beispiel 3.Wie viele Tickets? Gesamt: 180 €while (true) läuft immer weiter, bis break die Schleife beendet. Und break wird nur erreicht, wenn Parse Erfolg hat. Bei einem Fehler springt die Ausführung in catch, danach beginnt die Schleife von vorn und fragt noch einmal.
Genauer, für Neugierige
- Wenn eine falsche Eingabe etwas Normales ist, hat C# einen bequemeren Weg:
int.TryParse. Es wirft keine Exception. Es gibttrueoderfalsezurück und schreibt die Zahl in denout-Parameter aus der Lektion über Parameter:
int tickets;Console.Write("Wie viele Tickets? ");while (!int.TryParse(Console.ReadLine(), out tickets)){ Console.WriteLine("Gib eine ganze Zahl ein, zum Beispiel 3."); Console.Write("Wie viele Tickets? ");}Console.WriteLine("Gesamt: " + tickets * 15 + " €");Exceptions sind für Situationen, die du nicht oft erwartest. Zum Prüfen einer Eingabe ist TryParse kürzer und schneller.
Probier es aus
Division durch null
Nicht jede Exception kommt von der Eingabe. Der durchschnittliche Bestellwert ist der Umsatz geteilt durch die Zahl der Bestellungen. Aber am ersten Tag gibt es keine Bestellungen. Mit ganzen Zahlen hält revenue / orders das Programm an:
Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.Und mit Kommazahlen?
Was gibt das Programm aus?
int revenue = 90;int orders = 0;double average = (double)revenue / orders;Console.WriteLine(average);NaN („keine Zahl“). Das Programm läuft mit einem falschen Wert weiter, ohne etwas zu sagen. Prüfe deshalb vor so einer Division den Divisor mit if.Genauer, für Neugierige
- Hier ist die Ausgabe
Infinity. Auf einem Computer mit Regionaleinstellungen, zum Beispiel deutschen oder amerikanischen, gibt C# das Zeichen∞aus.
- Ganze Zahlen haben keinen Wert für unendlich, deshalb bleibt dort nur die Exception. Für Kommazahlen kommen die Regeln aus dem Standard IEEE 754 für Gleitkommazahlen, dem alle Sprachen folgen.
Übung
Programme, die nicht anhalten
Löse die Aufgaben in deinem Editor. Gib keine Eingabeaufforderungen aus, damit deine Ausgabe mit dem Beispiel übereinstimmt.
1. Text zu Zahl. Schreibe eine Methode ToNumber(string text), die den Text als double zurückgibt. Lies zwei Zeilen. Gib für jede die Zahl aus oder eine Meldung, dass es keine Zahl ist. Fange die Exception in Main.
123.45123.abcDie Zahl ist: 123.45Fehler: 123.abc ist keine Zahl.Auf einem Computer mit deutschen Regionaleinstellungen will double.Parse ein Komma: 123,45. Siehe die Lektion „Eingabe und Ausgabe“.
2. Kein solches Produkt. Die Preise stehen im Array { 120, 75, 300, 45, 89 }. Lies eine Produktnummer von 1 bis 5 und gib ihren Preis aus. Wenn die Nummer außerhalb des Arrays liegt, fange die Exception und sag es. Mit der Eingabe 2 ist die Ausgabe Preis: 75 €.
7Es gibt kein Produkt mit der Nummer 7.3. Durchschnittliche Bestellung. Lies den Umsatz und die Zahl der Bestellungen (ganze Zahlen) und gib den Durchschnitt mit Ganzzahldivision aus. Wenn es keine Bestellungen gibt, fange die Exception. Mit der Eingabe 900 und 4 ist die Ausgabe Durchschnitt: 225 €.
900Noch keine Bestellungen.Weitere Aufgaben
- Alter, bis es stimmt. Frage nach dem Alter, bis die Eingabe eine ganze Zahl von 0 bis 120 ist. Bei Text wie „zwanzig“ sag „Das ist keine Zahl.“, und bei 150 sag „Das Alter muss zwischen 0 und 120 liegen.“ Das eine ist eine Exception, das andere ein
if. - Summe der gültigen. Lies 5 Zeilen. Addiere die, die ganze Zahlen sind, und zähle die übersprungenen: Mit der Eingabe
10,abc,5,7.5,3ist die AusgabeSumme: 18, übersprungen: 2. - Division auf Wunsch. Lies zwei ganze Zahlen und gib den Quotienten aus. Bei Text statt einer Zahl und bei Division durch null hält das Programm nicht an. Es fragt noch einmal nach beiden Zahlen.
- Ohne Exception. Löse Aufgabe 1 mit
double.TryParsestatt mittry/catch.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Parameter und return · Rekursion · Klassen und Objekte · Instanzmethoden
- Geht weiter in: try, catch und finally · Werfen und eigene Exceptions · Listen · Stack, Queue und verkettete Liste
- Aufgaben zum Thema: Fehler und Exceptions