WEBVTT

00:05.520 --> 00:08.120
Herzlich willkommen zur Programmieren-Vorlesung.

00:10.420 --> 00:15.080
Was wir heute machen werden, sind voraussichtlich zwei Teile.

00:15.220 --> 00:17.100
Einmal das Thema Ausnahmebehandlung.

00:17.800 --> 00:22.700
Das brauchen Sie, weil das auch auf dem Übungsblatt auftaucht.

00:23.540 --> 00:26.320
Und ich habe den Eindruck, dass ich diesmal besonders laut bin.

00:27.900 --> 00:28.980
Mal hier ein bisschen leiser.

00:29.800 --> 00:32.800
Nach der Mensa muss man aber in Ruhe vielleicht irgendwo sitzen

00:32.800 --> 00:33.240
können.

00:35.240 --> 00:36.400
Besser so von der Lautstärke?

00:37.840 --> 00:39.020
Keiner schreit, okay, alles gut.

00:40.460 --> 00:43.760
Das andere ist, ich habe noch eine kleine Weihnachtsvorlesung dabei.

00:45.420 --> 00:47.960
Jetzt können Sie sich danach darüber wundern, was ich lustig finde,

00:48.120 --> 00:50.400
aber vielleicht findet es auch der eine oder andere von Ihnen nett.

00:51.900 --> 00:54.980
Und insofern will ich das auch nicht ganz unerwähnt lassen, dass ja

00:54.980 --> 00:57.720
die letzte Vorlesungswoche in diesem Jahr ist und die letzte

00:57.720 --> 00:58.940
Vorlesung, der wir uns sehen.

00:59.740 --> 01:02.140
So, wo sind wir jetzt angekommen?

01:02.520 --> 01:04.780
Im Prinzip haben wir, wie Sie sehen, jetzt schon vor Weihnachten eine

01:04.780 --> 01:06.780
ganze Menge Themen behandelt.

01:08.420 --> 01:10.580
Das hier ist nämlich ganz falsch, weil ich habe die Exceptions

01:10.580 --> 01:11.340
-Vorlesung vorgezogen.

01:11.660 --> 01:14.700
Interfaces und Generics kommen nach Weihnachten noch dran.

01:15.620 --> 01:18.120
Was aber heute jetzt rankommt, sind hier diese Exceptions.

01:18.280 --> 01:21.960
Diesen Baustein machen wir noch voll, weil das eben für das

01:21.960 --> 01:23.160
Übungsblatt notwendig ist.

01:25.380 --> 01:33.280
Die Idee ist, dass ich Ihnen heute beibringe, dass Sie überlegen, wie

01:33.280 --> 01:37.260
gehe ich mit Fehlerzuständen um beim Programmieren?

01:37.860 --> 01:40.360
Wie kann ich systematisch Fehlerzustände erkennen und vor allem

01:40.360 --> 01:41.400
signalisieren und abfangen?

01:42.280 --> 01:45.140
Und wie kann man das machen, ohne dass die gesamte Programmlogik

01:45.140 --> 01:47.460
unnötig kompliziert wird?

01:51.160 --> 01:53.180
Wenn man sich mal überlegt...

01:53.180 --> 01:57.660
Bisher war das, was ich Ihnen als Beispiele programmiert habe, immer

01:57.660 --> 01:58.880
so Schönwetterprogramme.

01:59.020 --> 02:02.080
Unter der Annahme, dass alles so ist, wie es sein soll, laufen die

02:02.080 --> 02:05.700
halt durch und liefern gemäß dem Algorithmus das Ergebnis, das sie

02:05.700 --> 02:06.060
brauchen.

02:07.060 --> 02:12.340
Jetzt ist aber der Witz der, das Programm läuft natürlich auf einer

02:12.340 --> 02:16.420
Ablaufumgebung, Ihrem Computer ab, möglicherweise auch vernetzt.

02:16.420 --> 02:18.900
Es muss auf Remote-Dienste zugreifen.

02:19.620 --> 02:21.420
Und das können Sie sich natürlich sehr schnell vorstellen.

02:21.960 --> 02:24.740
Dann können Situationen entstehen, die eben nicht zum

02:24.740 --> 02:25.900
Schönwetterprogrammieren gehören.

02:25.960 --> 02:28.060
Wie zum Beispiel, es gibt gerade keine Netzwerkverbindungen.

02:28.580 --> 02:31.920
Oder Festleitbevoll oder Hauptspeicher bekomme ich nichts mehr

02:31.920 --> 02:32.340
zugewiesen.

02:33.100 --> 02:36.960
Und das sind eben Situationen, die Ausnahmen darstellen.

02:37.060 --> 02:39.740
Und deswegen auch der englische Wort Exception, Exception Handling.

02:41.080 --> 02:44.520
Und die Frage ist jetzt ja, wie kann man jetzt im Prinzip mit diesen

02:44.520 --> 02:48.780
Ausnahmesituationen umgehen ohne, dass der Programmtext unnötig

02:48.780 --> 02:49.540
kompliziert wird.

02:49.640 --> 02:51.140
Und hier erstmal so ein paar Gegenbeispiele.

02:52.780 --> 02:55.400
Diese GoTo-Anweisung habe ich Ihnen bisher immer so ein bisschen

02:55.400 --> 02:56.600
klammheimlich vorenthalten.

02:57.140 --> 03:00.480
Aber sinngemäß macht GoTo nichts anderes, als wenn ich an der Stelle

03:00.480 --> 03:05.400
bin, dass der Programm-Kontrollfluss dahin springt, wo die Marke ist.

03:05.500 --> 03:08.700
Also hier sehen Sie mal GoTo, dann so eine Marke Error oder Loop Exit.

03:09.180 --> 03:11.180
Und dann springt man halt, wenn ich jetzt hier bei GoTo Error bin,

03:11.600 --> 03:14.140
wenn ich da bin bei GoTo, dann heißt das, ich mache hier weiter.

03:14.840 --> 03:15.900
Und überspringe den Rest.

03:16.100 --> 03:18.260
Das ist die Idee von einem GoTo, falls Sie das noch nicht kennen.

03:19.700 --> 03:23.460
Und früher hat man tatsächlich, als man mit GoTos programmiert hat,

03:23.540 --> 03:27.420
das war vor allem in den 60ern, aber danach wusste man eigentlich, wie

03:27.420 --> 03:30.560
es besser geht, hat das aber vielleicht nicht immer gemacht, hat man

03:30.560 --> 03:35.100
dann gesagt, naja, wenn ich also jetzt hier abfrage, hat das geklappt,

03:35.180 --> 03:37.420
war das erfolgreich oder gab es einen Fehler, dann sage ich nicht GoTo

03:37.420 --> 03:37.760
Error.

03:37.900 --> 03:38.700
Dann springt man dahin.

03:40.220 --> 03:44.360
Und ansonsten sagt man halt, ich möchte die Schleife beenden, springt

03:44.360 --> 03:44.720
dahin.

03:44.780 --> 03:46.720
Das ist quasi die Schleifenabbruchbedingung hier.

03:47.280 --> 03:50.160
Und am Ende der Schleife sagt man noch mal GoTo Loop und sorgt dafür,

03:50.300 --> 03:51.300
dass man hier in der Schleife ist.

03:52.980 --> 03:56.340
So diese GoTos hat man mal irgendwann wegbekommen, indem man gesagt

03:56.340 --> 03:58.460
hat, das kann man eigentlich mit While und If machen.

03:58.900 --> 04:01.980
Vielleicht nicht immer genauso super effizient, aber im Prinzip ist

04:01.980 --> 04:05.920
das viel leichter verständlich, wenn man die Schleifenkonstrukte

04:05.920 --> 04:06.140
nimmt.

04:06.240 --> 04:09.080
Man braucht eigentlich nicht wirklich GoTos, aber für die

04:09.080 --> 04:13.780
Fehlerbehandlung ist das, was man auch lange noch gesehen hat.

04:13.880 --> 04:17.960
Und eigentlich bietet natürlich auch C++ GoTos an, also insofern kann

04:17.960 --> 04:19.260
man das natürlich genauso da so machen.

04:21.600 --> 04:24.160
Wenn man sagt, naja, jetzt will ich aber keine GoTos verwenden, dann

04:24.160 --> 04:27.880
gibt es natürlich eine andere Möglichkeit, nämlich, dass man sich so

04:27.880 --> 04:32.500
ein kleines Flag, also wenn man so will, eine Boolean-Variable oder

04:32.500 --> 04:37.440
auch eine Integer-Variable setzt, mit einem Wert, der signalisiert,

04:38.100 --> 04:40.520
hatte ich einen Fehlerzustand, hatte ich eine Ausnahme gehabt?

04:41.180 --> 04:43.940
Wenn ja, muss ich an irgendeiner anderen Stelle, wo ich dann dieses

04:43.940 --> 04:47.720
Flag abfrage, mich darum kümmern, dass jetzt gerade eine Ausnahme

04:47.720 --> 04:50.440
passiert ist und ich damit irgendwie gesondert umgehen muss.

04:50.900 --> 04:54.180
Und hier sieht man auch wieder das Beispiel, eigentlich wie eben, dass

04:54.180 --> 04:57.800
man sagt, ich erkenne hier einen Fehler und setze jetzt Error auf True

04:57.800 --> 05:02.880
und die Sache, ich setze auch Quit auf True und im Prinzip wird die

05:02.880 --> 05:05.520
Schleife so lange gelaufen, wie eben nicht Quit gesetzt ist.

05:05.880 --> 05:09.380
Hier setze ich es, das heißt also, hier unten gehe ich raus und dann

05:09.380 --> 05:12.460
frage ich nach, ist noch ein Fehlerzustand aufgetaucht?

05:13.120 --> 05:16.200
Und wenn Error True ist, also ich in dem L-Zweig bin, dann mache ich

05:16.200 --> 05:17.060
halt die Fehlerbehandlung.

05:17.660 --> 05:21.560
Jetzt habe ich zwar die GoTos vermieden alle, großartig, aber wenn man

05:21.560 --> 05:25.340
mal ehrlich ist, das ist von der Verständlichkeit auch nicht viel

05:25.340 --> 05:27.520
besser geworden, auch dass ich jetzt die GoTos weg habe.

05:28.020 --> 05:30.860
Ich habe genauso viele Ifs, ich muss genauso lange drüber nachdenken.

05:32.840 --> 05:35.440
Hier setze ich was, hier unten muss ich es wieder an anderer Stelle

05:35.440 --> 05:36.120
auswerten.

05:37.700 --> 05:39.740
Irgendwie alles kompliziert und vor allem jetzt, wenn man sich

05:39.740 --> 05:44.660
überlegt, Error und Quit sind ja lokale Variablen, das heißt, im

05:44.660 --> 05:47.780
Aufrufkontext sind die gar nicht mehr auslesbar.

05:48.000 --> 05:51.560
Die sind ja nur für mich in meiner Routine jetzt gerade noch gültig.

05:52.080 --> 05:55.560
Das heißt, mit anderen Worten, wenn ich jetzt woanders die

05:55.560 --> 05:58.940
Fehlerbehandlung machen wollte, als direkt hier nach, habe ich auch

05:58.940 --> 05:59.420
ein Problem.

06:02.500 --> 06:17.040
Diese lokale Fehlerbehandlung ist halt im Prinzip keine so schöne

06:17.040 --> 06:19.140
Sache, weil es das Programm eher schlechter lesbar macht.

06:19.840 --> 06:22.520
Diejenigen von Ihnen, die vielleicht schon ein bisschen was in C

06:22.520 --> 06:24.940
programmiert haben, kennen so grob das Folgende.

06:25.080 --> 06:28.700
Ich mache irgendwas und frage dann nachher nach, war die Operation

06:28.700 --> 06:32.380
erfolgreich und wenn sie das nicht war, in dem Fall jetzt hier über

06:32.380 --> 06:37.440
die Rückgabe von OpenFile gelesen, dann muss ich halt die

06:37.440 --> 06:38.400
Ausnahmebehandlung machen.

06:38.500 --> 06:41.720
Was man jetzt sieht ist, ich mache die Ausnahmebehandlung immer sehr

06:41.720 --> 06:43.660
nah an der Stelle, wo das Problem aufgetaucht ist.

06:43.740 --> 06:44.780
Das geht nicht immer.

06:45.660 --> 06:48.580
Und ich verschmiere eigentlich auch so zwei Belange.

06:48.740 --> 06:51.400
Und Sie erinnern sich vielleicht an dieses Thema Separation of

06:51.400 --> 06:53.780
Concern, Trennung der Belange.

06:53.920 --> 06:57.020
Ich habe einmal die normale Programmlogik und habe auf einmal so eine

06:57.020 --> 07:01.260
Userinteraktion hier an der Stelle mitten in der Programmlogik.

07:01.340 --> 07:02.080
Das ist nicht schön.

07:02.380 --> 07:03.960
Das will man eigentlich sauber trennen.

07:04.060 --> 07:06.680
Das eine ist nämlich das Tun, was man tun soll, und das andere ist die

07:06.680 --> 07:07.700
Ausnahmebehandlung.

07:09.280 --> 07:13.500
Das sind eigentlich alles die Gründe, warum man sich mal überlegt hat,

07:13.560 --> 07:16.680
beim Entwurf von Sprachen, kann man das nicht eigentlich besser

07:16.680 --> 07:19.200
machen, indem man die Sprache anreichert mit einem zusätzlichen

07:19.200 --> 07:19.660
Konstrukt.

07:19.780 --> 07:21.980
Weil jetzt haben wir ja bisher immer das Thema Fehlerbehandlung nur

07:21.980 --> 07:23.120
über die Standardkonstrukte gemacht.

07:23.260 --> 07:28.840
Sei es GOTO, sei es IFS und FLAGS, sei es Abfragen von Rückgabewerten.

07:29.800 --> 07:32.540
Und die Antwort ist halt das Exception-Konzept.

07:33.820 --> 07:37.640
Und hier sagt man halt, ich habe eine Exception, das ist eine

07:37.640 --> 07:39.020
Ausnahmesituation im Programmablauf.

07:40.460 --> 07:43.020
Der normale Kontrollfluss kann an der Stelle nicht sinnvoll mehr

07:43.020 --> 07:44.220
weiter durchgeführt werden.

07:45.220 --> 07:49.920
Und ich möchte jetzt in der Lage sein, anderen Stellen im Programm,

07:50.000 --> 07:52.540
die möglicherweise relativ weit weg entfernt sind von der Stelle, wo

07:52.540 --> 07:55.400
der Fehler aufgetaucht ist, darauf zu reagieren.

07:55.620 --> 07:56.700
Und warum will man das?

07:57.320 --> 08:03.440
Naja, weil eben manchmal muss man Informationen aus dem Aufrufkontext

08:03.440 --> 08:06.420
haben, um zu wissen, wie ich mit dem Fehler an der Stelle umgehen

08:06.420 --> 08:06.660
soll.

08:06.740 --> 08:09.680
Ich kann manchmal nicht sinnvoll sagen, wie gehe ich jetzt mit der

08:09.680 --> 08:12.680
Ausnahmesituation um, an der Stelle, wo die Ausnahme aufgetaucht ist,

08:12.900 --> 08:16.260
sondern ich muss im Prinzip genauer wissen, wozu habe ich das

08:16.260 --> 08:16.860
eigentlich gemacht?

08:17.140 --> 08:19.260
Was wollte ich denn eigentlich im übergeordneten Sinne?

08:19.800 --> 08:23.260
Und das weiß man aber natürlich nicht an der Routine und an der

08:23.260 --> 08:25.780
Stelle, wo ich eigentlich war, sondern manchmal erst beim Aufrufer der

08:25.780 --> 08:26.640
Routine selber wieder.

08:27.120 --> 08:30.180
Und dieses Signalisieren auch über die Aufruf-Hierarchie hinweg von

08:30.180 --> 08:33.680
Methoden, das ist eben mit Exceptions relativ leicht möglich und ist

08:33.680 --> 08:36.240
halt mit den Flags nur sehr kompliziert, weil dann müsste man die

08:36.240 --> 08:39.700
Flags nämlich als globale Variable deklarieren und das hat eine Menge

08:39.700 --> 08:40.400
anderer Nachteile.

08:41.960 --> 08:46.080
In Java ist das Ganze so umgesetzt, es gibt, weil Java

08:46.080 --> 08:49.540
objektorientiert ist, erst mal die Exceptions als Objekte.

08:49.640 --> 08:54.720
Das heißt, die werden mit new erzeugt, aber jetzt gibt es schon drei

08:54.720 --> 08:57.360
neue Schlüsselwörter, die wir jetzt auch einführen, und zwar einmal

08:57.360 --> 09:01.500
throw für das Auslösen der Exception, dann catch, das können wir

09:01.500 --> 09:04.480
gleich hören, und dann nochmal das Wort throws, also das throw mit dem

09:04.480 --> 09:05.880
s noch mal dran ist nochmal etwas anderes.

09:07.320 --> 09:09.060
Schauen wir uns das Beispiel mal hier an.

09:09.740 --> 09:16.120
Ich habe eine Routine, in der ich den Monat setzen möchte.

09:16.720 --> 09:20.460
Der Monat wird durch einen Integer codiert und es ist irgendwo klar,

09:20.640 --> 09:25.020
dass der Wert irgendwo zwischen 1 und 12 liegen muss, und wenn er

09:25.020 --> 09:28.740
kleiner 1 ist oder größer als 12, dann ist das offenbar nicht sinnvoll

09:28.740 --> 09:31.120
abbildbar auf dem Monat, zumindest mal nicht in den Kalender, die wir

09:31.120 --> 09:35.500
haben, und insofern kann man sagen, ist das eigentlich eine

09:35.500 --> 09:38.760
Ausnahmesituation im Sinne, dass offenbar diese Routine setMonths

09:38.760 --> 09:40.760
falsch anprogrammiert wurde.

09:41.260 --> 09:44.680
Wir werden uns das gleich noch im Detail anschauen, es gibt im

09:44.680 --> 09:49.340
Prinzip, aber grob gesagt, einmal die Exceptions, die dadurch

09:49.340 --> 09:53.720
passieren, weil in der Umgebung was nicht stimmt, Dateisystem voll,

09:54.020 --> 09:59.320
Netzwerkverbindung abgerissen, oder weil im Programmcode was falsch

09:59.320 --> 10:02.580
ist, was ich an der Stelle jetzt hier bemerke, wo der Fehler also

10:02.580 --> 10:04.600
nicht in der Ausführungsumgebung liegt, sondern eigentlich der Fehler

10:04.600 --> 10:07.520
bei mir selber oder bei einem anderen Programmierer, der die Routine

10:07.520 --> 10:08.040
verwendet.

10:08.260 --> 10:11.140
Das Letztere ist hier der Fall, das ist ja kein Fehler der

10:11.140 --> 10:13.900
Ausführungsumgebung, wenn jetzt hier bei IntMonths 13 übergeben wurde

10:13.900 --> 10:16.620
als aktueller Parameter, sondern das ist ein Fehler beim

10:16.620 --> 10:19.740
Anprogrammieren, aber den möchte ich hier an der Stelle abfangen, weil

10:19.740 --> 10:23.120
offenbar kann das Programm so nicht klappen.

10:24.220 --> 10:27.520
Und dann seht ihr hier, das ist dann auch normal in Java so, ich habe

10:27.520 --> 10:31.680
eine Exception, die ist in dem Sinne sogar schon vordefiniert,

10:33.200 --> 10:35.480
IllegalArgumentException und die wird mit new erzeugt und dann

10:35.480 --> 10:39.980
schreibt man davor throw und dann wird dieses Objekt erzeugt und dient

10:39.980 --> 10:41.020
zur Signalisierung.

10:42.260 --> 10:45.020
So wie das jetzt gleich behandelt wird, sehen wir später.

10:46.000 --> 10:48.600
Erstmal noch geradezu, was für Exception gibt es eigentlich?

10:49.220 --> 10:51.520
In Java gibt es schon eine Klasse Exception.

10:51.640 --> 10:54.840
Das ist, wenn man so will, die allgemeinste Klasse, die Oberklasse,

10:54.980 --> 10:58.100
Sie erinnern sich, alle anderen erben davon, also Vererbungen nutzen

10:58.100 --> 10:59.760
wir hier, was wir das letzte Mal kennengelernt haben.

11:02.500 --> 11:06.300
Und diese Klasse Exception nutzen Sie im Wesentlichen eigentlich nur

11:06.300 --> 11:09.480
dafür, um selber Ihre eigenen Exceptions davon abzuleiten.

11:09.580 --> 11:12.360
Also Sie schreiben dann im Prinzip hin, Inherit, Extends, Exception.

11:12.860 --> 11:13.320
So.

11:15.760 --> 11:19.540
Und diese Klasse braucht mindestens einen Default-Konstruktor und Sie

11:19.540 --> 11:21.820
brauchen einen Konstruktor mit einem String-Parameter Ihrer Klasse.

11:22.300 --> 11:25.880
Der String-Parameter ist quasi eine Beschreibung von dem, was jetzt

11:25.880 --> 11:28.740
nochmal genau die Ursache war, um noch etwas genauer zu sagen, nicht

11:28.740 --> 11:31.020
nur diese Klasse von Exception ist aufgetaucht, sondern genau an der

11:31.020 --> 11:31.940
Stelle ist sie aufgetaucht.

11:32.420 --> 11:33.740
Oder mit aus der Ursache heraus.

11:34.400 --> 11:40.300
Und es gibt wichtige Methoden am GetMessage, um diesen String zu

11:40.300 --> 11:42.800
bekommen, den Sie hier beim Konstruktor mit übergeben haben.

11:43.220 --> 11:47.440
Das erben Sie aber von der Exception-Klasse.

11:48.300 --> 11:52.720
PrintStackTrace gibt den Aufruf-Stack zurück, um zu wissen, unter

11:52.720 --> 11:56.640
Umständen, wenn ich das ganze Programm abbrechen muss komplett, dass

11:56.640 --> 11:59.280
ich dem Benutzer noch wenigstens sagen kann, an welcher Stelle im

11:59.280 --> 12:01.560
Programmcode war es gewesen, weil das natürlich bei der Fehlersuche

12:01.560 --> 12:02.120
nachher hilft.

12:04.480 --> 12:10.160
Und man kann auch den StackTrace sich quasi nicht gleich als ausgeben

12:10.160 --> 12:12.920
lassen auf dem Bildschirm, sondern auch sich selber als

12:12.920 --> 12:15.480
Strukturelement ausgeben lassen, als Array hier.

12:17.200 --> 12:20.000
Und das ist diese Routine hier, GetStackTrace.

12:21.580 --> 12:24.620
So, es gibt zusätzlichen Java auch noch eine Klasse Error.

12:25.420 --> 12:29.200
Error ist etwas, damit werden Sie in dem Sinne vielleicht deutlich

12:29.200 --> 12:31.740
seltener in der Praxis zu tun haben, als mit Exception.

12:32.680 --> 12:36.180
Exception ist das, was Sie nutzen, um selber Ihre eigenen Ausnahmen

12:36.180 --> 12:37.950
spezifisch typisch für Ihre Anwendung abzuleiten.

12:38.920 --> 12:43.340
Von Error ist es eigentlich so, dass man meiner Erfahrung nach

12:43.340 --> 12:44.640
eigentlich gar nicht so viel ableitet.

12:45.100 --> 12:48.260
Das erwähne ich nur deswegen, weil es in Java auch so vorgesehen ist.

12:48.340 --> 12:51.200
Nämlich, die ganze Hierarchie sieht so aus.

12:53.280 --> 12:56.340
Es gibt quasi auslösbare Events.

12:56.480 --> 12:58.460
Davon ist eins das Exception, was wir besprochen haben.

12:58.560 --> 12:59.480
Das andere ist ein Error.

13:00.300 --> 13:03.160
Und Sie sehen schon, Error, das sind eigentlich die Dinge, die man

13:03.160 --> 13:04.720
nicht sinnvoll mehr behandeln kann.

13:05.700 --> 13:08.260
Das heißt zum Beispiel, es gibt einen Bug in der virtuellen Maschine.

13:08.580 --> 13:11.000
In der JVM ist ein Fehler drin.

13:11.740 --> 13:13.720
Und das führt zu einem inkonsistenten Programmzustand.

13:13.780 --> 13:14.840
Das will man signalisieren.

13:15.580 --> 13:17.480
Aber da kann man nichts mehr machen.

13:17.560 --> 13:20.040
Das ist genauso, wie wenn man sagt, die Naturgesetze gelten nicht

13:20.040 --> 13:20.220
mehr.

13:23.340 --> 13:28.420
So, und hier bei Exception, das ist im Prinzip die interessante

13:28.420 --> 13:30.900
Klasse, wo Sie auch weitere Sachen ableiten können.

13:31.460 --> 13:34.140
Und da gibt es schon vordefiniert die sogenannte Runtime Exception.

13:34.260 --> 13:38.260
Und die Runtime Exception, das sind die Dinge, die signalisieren,

13:38.760 --> 13:41.060
offenbar ist beim Programmieren was schiefgegangen.

13:41.280 --> 13:45.240
Also nicht die Ablaufumgebung klemmt, sondern beim Programmieren ist

13:45.240 --> 13:45.900
was schiefgegangen.

13:46.040 --> 13:47.860
Das kann ein Nullpointer sein.

13:47.960 --> 13:50.120
Das heißt, ich habe einen Nullpointer übergeben bekommen.

13:50.120 --> 13:54.620
Also den Wert Null für eine Objektreferenz, wo er nicht stehen sollte.

13:55.420 --> 13:57.760
Und das ist offenbar beim Programmieren vorher schiefgegangen.

13:58.420 --> 14:03.360
Oder ein Arrayindex geht außerhalb des Bereichs.

14:03.400 --> 14:05.880
Oder ich habe im Prinzip eine Arithmetic Exception, das ist zum

14:05.880 --> 14:11.600
Beispiel, wenn eine mathematische Operation durchgeführt wird, wie sie

14:11.600 --> 14:13.020
aber eigentlich nicht spezifiziert ist.

14:13.360 --> 14:16.140
Teilen durch Null, das hatten wir ja schon mal behandelt, wie das bei

14:16.140 --> 14:16.820
Integers bzw.

14:17.120 --> 14:20.120
bei Bubbles ist, bei Gleitkommazahlen.

14:21.320 --> 14:25.820
Es kann aber auch sein, dass Sie im Prinzip Genauigkeitsprobleme

14:25.820 --> 14:28.040
haben, das können Sie alles hier mit der Arithmetic Exception

14:28.040 --> 14:28.300
kodieren.

14:28.400 --> 14:29.680
Die sind also, wie gesagt, schon vordefiniert.

14:30.020 --> 14:32.220
Es gibt auch noch ein paar mehr, das ist nur ein Auszug aus der

14:32.220 --> 14:33.020
Exception -Hierarchie.

14:33.780 --> 14:35.940
Aber wichtig ist eigentlich, dass Sie diese Unterscheidung hier

14:35.940 --> 14:37.660
kennen, Error und Exception.

14:37.780 --> 14:41.500
Error ist, wie gesagt, die Ablaufumgebung, wo Sie nichts machen

14:41.500 --> 14:41.860
können.

14:42.420 --> 14:46.740
Wenn die Javavirtual-Maschine es falsch, nicht klappt oder Bugs hat

14:46.740 --> 14:48.600
oder inkonsistente Zustände hat, dann können Sie programmieren, was

14:48.600 --> 14:49.000
Sie wollen.

14:52.160 --> 14:56.560
Und die Exceptions, wo Sie in der Regel Ihre Ausnahmen ableiten.

14:56.660 --> 14:58.300
Und davon ist die Unterscheidung hier wichtig.

14:59.140 --> 15:02.500
Laufzeitexceptions, also eher Fehler in der internen Programmlogik,

15:02.560 --> 15:04.960
die Sie aber irgendwann erkennen und sagen, jetzt möchte ich darauf

15:04.960 --> 15:05.360
reagieren.

15:05.780 --> 15:10.500
Oder aber die Ablaufumgebung selber meldet einen Fehler.

15:10.860 --> 15:11.460
Vordefiniert ist z.B.

15:11.480 --> 15:14.780
die IO-Exception und davon nochmal der Spezialfall FileNotFound

15:14.780 --> 15:15.720
-Exceptions.

15:15.900 --> 15:16.180
Also z.B.

15:16.200 --> 15:18.280
eine Datei sollte geöffnet werden, aber die ist gar nicht da.

15:19.420 --> 15:22.260
Und jetzt kann man ja schon irgendwo einsehen, das hier ist nicht so

15:22.260 --> 15:24.300
ganz fatal, wie z.B.

15:24.460 --> 15:25.180
jetzt hier sowas.

15:26.500 --> 15:29.340
Hier an der Stelle, FileNotFound, hat sich vielleicht der Benutzer

15:29.340 --> 15:31.120
irgendwo mal vertippt in den Dateinamen.

15:32.660 --> 15:37.240
Das heißt, man kann ihn noch mal bitten, die Dateinamen einzugeben.

15:37.320 --> 15:40.000
Und man kann ihm auch die Fehlermeldung ausgeben, um sagen, hier, die

15:40.000 --> 15:40.960
Datei wurde nicht gefunden.

15:41.480 --> 15:44.500
Und man kann eben hoffen, dass durch zusätzliche Interaktionen oder

15:44.500 --> 15:47.820
durch zusätzlichen Programmcode ich das Problem in den Griff bekomme.

15:49.740 --> 15:54.320
Hier habe ich in der Regel nicht so viele Sachen, wie ich das Ganze

15:54.320 --> 15:56.140
wieder in den Griff bekommen kann, weil ja offenbar irgendwo ein

15:56.140 --> 15:57.380
Programmierfehler vorliegt.

15:57.680 --> 16:01.360
Und es macht eigentlich auch wenig Sinn, Programmierfehler anderer

16:01.360 --> 16:05.060
Programmierer jetzt durch wahnsinnig viele schlauen Raten, wie könnte

16:05.060 --> 16:08.160
man das doch noch sinnvoll korrigieren, in den Griff zu bekommen.

16:08.900 --> 16:11.140
Aber hier, das ist trotzdem noch was anderes wie das hier.

16:11.200 --> 16:14.680
Das hier ist im Prinzip etwas, was wie gesagt nicht korrigierbare

16:14.680 --> 16:16.840
Fehler in der Ablaufumgebung sind, wo man einfach das Programm

16:16.840 --> 16:17.880
definitiv abbrechen muss.

16:18.100 --> 16:19.880
Hier muss man es meistens auch abbrechen.

16:19.980 --> 16:22.080
Aber wie gesagt, der Grund ist ja hier ein anderer.

16:22.220 --> 16:25.600
Hier ist es der Fehler beim Programmieren Ihrer Anwendung gewesen, sei

16:25.600 --> 16:27.640
es von Ihnen oder von einem Ihrer Programmierer-Kollegen.

16:28.280 --> 16:31.160
Hier ist es der Fehler, wie gesagt, in der Ablaufumgebung, die andere

16:31.160 --> 16:33.720
Leute programmiert haben und auf der sie einfach aufbauen müssen.

16:33.820 --> 16:36.140
Und das ist der Unterschied quasi zwischen Error und Runtime

16:36.140 --> 16:36.520
Exception.

16:38.060 --> 16:40.860
Wie gesagt, in der Praxis ist eigentlich das wichtige Wissen für Sie.

16:41.020 --> 16:44.420
Sie leiten Ihre Dinge von Exception ab und Sie sollten wissen, es gibt

16:44.420 --> 16:44.980
zwei Klassen.

16:45.120 --> 16:47.120
Einmal in der Ablaufumgebung geht was schief, was ich hoffentlich

16:47.120 --> 16:47.780
korrigieren kann.

16:47.840 --> 16:49.940
Dann bin ich hier unterwegs und leite hiervon weiter ab.

16:50.820 --> 16:53.540
Oder leite meine Sachen daneben ab, aber es ist so wie das.

16:53.620 --> 16:56.740
Oder ich habe eine Ableitung von Runtime Exception und das ist halt

16:56.740 --> 16:58.740
was, wenn wir mal programmieren, was schiefgegangen ist.

16:59.140 --> 16:59.760
So, puh.

17:00.500 --> 17:01.640
Wie geht es jetzt weiter?

17:01.920 --> 17:04.800
Ich kann also mit Throw New eine Exception auslösen.

17:05.600 --> 17:07.060
Jetzt muss aber sicher einer darum kümmern.

17:07.600 --> 17:10.020
Sagen, okay, offenbar ist jetzt dieser inkonsistente Zustand

17:10.020 --> 17:10.880
entstanden.

17:11.500 --> 17:13.860
Jetzt möchte ich was Schlaues machen, um diesen Fehler zu beheben oder

17:13.860 --> 17:15.340
zumindest um damit umzugehen.

17:16.160 --> 17:19.460
Und das ist jetzt genau dieser sogenannte Catch-Block.

17:21.580 --> 17:26.420
Catch heißt, wenn im umgehenden Block eine Ausnahme ausgelöst wird,

17:26.520 --> 17:29.680
dann spring sofort hierhin und führe jetzt hier diesen sogenannten

17:29.680 --> 17:32.500
Exception -Handler diese Fehlerbehandlung aus.

17:33.360 --> 17:40.320
Und damit quasi der Java-Compiler weiß, um welchen Block-Code es sich

17:40.320 --> 17:44.920
hier handelt, ab wo kann die Ausnahme auftauchen und ab wo soll sie an

17:44.920 --> 17:48.780
der Stelle dann auch behandelt werden, eine aufgetauchte Sache, gibt

17:48.780 --> 17:49.800
es hier dieses Try-Board.

17:49.960 --> 17:53.760
Try fängt quasi an, geschweifte Klammer, dann schreiben sie den Code,

17:53.880 --> 17:56.320
wo potenzielle Exceptions auftauchen, am Ende, geschweifte Klammer zu,

17:56.440 --> 18:00.800
Catch und dann die Exception-Typen, die auftauchen können und es ist

18:00.800 --> 18:04.060
immer so, der erste, der gematcht wird, wird auch ausgeführt.

18:04.140 --> 18:07.880
Das heißt also, wenn Sie hier eine Oberklasse hinschreiben, wird das

18:07.880 --> 18:09.320
Spezielle hier unten nicht mehr ausgeführt.

18:09.420 --> 18:11.700
Das heißt, Sie müssen immer mit dem Speziellen anfangen und sollten

18:11.700 --> 18:13.280
mit den allgemeineren Klassen aufhören.

18:16.080 --> 18:17.600
So, hier sehen wir das mal am Beispiel.

18:19.420 --> 18:23.980
Sie instanziieren hier einen Dateileser, FileReader für die Datei Test

18:23.980 --> 18:29.820
.txt und jetzt kann es natürlich sein, dass diese Datei Test.txt nicht

18:29.820 --> 18:30.640
zugreifbar ist.

18:33.020 --> 18:36.820
Anstelle aber, dass Sie das jetzt hier direkt nach dem Aufruf von fr

18:36.820 --> 18:41.780
prüfen, sagen Sie einfach nur in diesem Block können Exceptions

18:41.780 --> 18:46.780
auftauchen, Versuche das und dann, wenn eben die FileNotFoundException

18:46.780 --> 18:49.680
kommt, dann ist jetzt unsere Fehlerbehandlung hier jetzt mal trivial.

18:50.200 --> 18:52.040
Man sagt einfach nur, die Datei will nicht gefunden werden.

18:52.220 --> 18:55.280
Wie gesagt, in echt könnte es ja heißen, dass Sie nochmal bitten,

18:55.320 --> 18:58.480
einen neuen Dateinamen einzugeben oder sonst was machen.

18:58.540 --> 19:00.460
Nur sagen, ich warte jetzt, bis die Datei da ist oder so.

19:01.920 --> 19:04.740
Und dann danach gibt es nochmal eine zweite Exception, die abgefangen

19:04.740 --> 19:08.480
wird, eine Eingehausgabefehler wird abgefangen.

19:08.980 --> 19:11.460
Und Sie erinnern sich an die Hierarchie, die ich eben vorgestellt

19:11.460 --> 19:11.780
hatte.

19:11.780 --> 19:16.440
Die FileNotFoundException ist abgeleitet von der IOException.

19:17.760 --> 19:21.660
Und das heißt mit anderen Worten, das hier ist die speziellere Klasse

19:21.660 --> 19:24.960
und die steht, wie es auch richtig ist, oben und die allgemeinere

19:24.960 --> 19:25.420
steht unten.

19:25.540 --> 19:29.500
Und das ist wie gesagt deswegen, weil eben der Catchblock ausgewählt

19:29.500 --> 19:31.700
wird, wo sofort drauf gematcht wird.

19:31.780 --> 19:34.960
Und wenn ich die IOException oben hingeschrieben hätte, dann würde

19:34.960 --> 19:38.320
FileNotFoundException, weil es ja eine Unterklasse von IOException

19:38.320 --> 19:39.440
ist, das würde matchen.

19:39.860 --> 19:43.660
Und dann würde halt immer IOException ausgeführt werden, wohingegen

19:43.660 --> 19:47.340
bei der FileNotFoundException, die würde nie ausgeführt werden, weil

19:47.340 --> 19:50.780
eben alle FileNotFoundException eben auch immer eine IOException sind.

19:51.220 --> 19:54.120
Und deswegen, wie gesagt, diese Regel von der spezielleren Klasse,

19:54.240 --> 19:57.180
also möglichst weit der Unterklasse, möglichst tief im Vererbungsbaum

19:57.180 --> 20:00.740
und dann erst darunter die sukzessive Oberklassen nehmen.

20:01.660 --> 20:06.180
Um eben die spezielle Behandlung zu auch immer am ehesten matchen

20:06.180 --> 20:06.540
können.

20:10.500 --> 20:14.180
So, wie gesagt, an der Stelle kann eben FileNotFound auftauchen und

20:14.180 --> 20:19.000
dann würde man eben hier hinspringen und hier würde man die wieder

20:19.000 --> 20:19.500
einfangen.

20:20.100 --> 20:25.800
Und dieses englische Throw und Catch, das sagt man auch quasi

20:25.800 --> 20:28.920
übersetzt in Deutsch, also man wirft Ausnahmen, hochdeutsch wäre

20:28.920 --> 20:32.780
vielleicht eher, man löst Ausnahmen aus und man fängt sie wieder ein

20:32.780 --> 20:33.200
mit Catch.

20:33.540 --> 20:34.760
So ist auch der Jargon an der Stelle.

20:34.760 --> 20:37.880
Jetzt werden Sie vielleicht zurecht fragen, ja Moment mal, wo steht

20:37.880 --> 20:39.080
denn hier dieses Throw?

20:39.820 --> 20:40.860
Und hier steht es ja gar nicht.

20:41.840 --> 20:45.440
Und die Antwort ist aber die, ja, das Throw kann natürlich hier,

20:45.540 --> 20:48.900
könnte ja drinstehen, aber es kann eben auch bei einer der

20:48.900 --> 20:50.400
aufgerufenen Routinen sein.

20:51.200 --> 20:54.700
Und in dem Fall ist es der FileReader, wo es ausgelöst werden kann.

20:54.780 --> 20:57.400
Und das werden wir uns nachher eben auch noch anschauen, wie das geht,

20:57.620 --> 21:01.280
dass Exceptions quasi über einen Methodenaufruf hinweg propagiert

21:01.280 --> 21:01.580
werden.

21:03.420 --> 21:05.820
Aber wie gesagt, hier, falls Sie jetzt verzweifelt das Throw-Wort

21:05.820 --> 21:08.360
gesucht haben, das steckt im Code von FileReader drin.

21:11.520 --> 21:13.960
So, das ist jetzt im Prinzip das, was ich schon erzählt habe, nur

21:13.960 --> 21:15.020
nochmal zum Nachlesen.

21:15.740 --> 21:18.540
Wenn ein Exception ausgelöst würde, wird der Programmfluss

21:18.540 --> 21:23.900
unterbrochen und man sucht eben im Aufruf-Stack jetzt nach der

21:23.900 --> 21:28.520
umgebenden Try-Catch-Umgebung und matcht halt den ersten Catch-Block,

21:28.640 --> 21:29.100
der passt.

21:29.580 --> 21:31.540
Und wie gesagt, das kann halt auch die Oberklasse sein, deswegen

21:31.540 --> 21:33.560
sollte die unten stehen und nicht oben.

21:35.360 --> 21:39.400
So, wenn das Ganze abgearbeitet wurde, geht man nicht mehr an die

21:39.400 --> 21:43.880
Stelle zurück, wo, also nochmal zurück hier, man geht, wenn das hier

21:43.880 --> 21:47.080
abgearbeitet wurde, nicht wieder an die Stelle zurück, wo es ausgelöst

21:47.080 --> 21:47.280
wurde.

21:47.360 --> 21:48.860
Also nicht wie ein Methodenaufruf.

21:49.220 --> 21:49.380
Warum?

21:49.560 --> 21:51.700
Naja, ich kann halt an der Stelle ja nicht weitermachen.

21:51.760 --> 21:54.960
Das war ja gerade die Idee von Exception.

21:55.080 --> 21:57.020
Ich kann mit der normalen Programmlogik nicht weitermachen.

21:57.100 --> 22:01.280
Deswegen springe ich eben nicht zurück hier zu FileReader.new, wo die

22:01.280 --> 22:04.220
Exception ausgelöst wurde, sondern ich gehe ans Ende von dem Catch

22:04.220 --> 22:04.360
-Block.

22:04.420 --> 22:06.040
Ich gehe auch nicht hierhin, sondern ich gehe dahin.

22:06.140 --> 22:08.540
Das erste wird gematched und danach gehe ich dahin.

22:09.440 --> 22:11.260
Es wird also auch nicht beides ausgeführt.

22:12.880 --> 22:16.260
Also nicht beide Catch-Blocke ausgeführt, sondern man geht immer

22:16.850 --> 22:17.060
dahin.

22:19.960 --> 22:24.800
So, hier sehen wir noch ein Beispiel.

22:25.940 --> 22:30.820
Und zwar jetzt über die Aufrufe über die Methodengrenzen hinweg.

22:31.520 --> 22:33.240
Wie wir das in dem Beispiel eben auch schon hatten.

22:33.340 --> 22:36.480
Wie ich gesagt habe, Sie haben in den drei Blocken gar kein Throw

22:36.480 --> 22:36.860
gefunden.

22:37.000 --> 22:39.740
Das war in dem FileOpen drin.

22:39.920 --> 22:42.500
Und hier ist es so, Sie haben jetzt hier eine Routine foo.

22:43.160 --> 22:45.480
Und da wird eine neue IO-Exception geworfen.

22:47.120 --> 22:49.280
Dann wird foo aufgerufen bei bar.

22:50.660 --> 22:54.160
Und buzz hat jetzt endlich mal den drei Catch-Block, wo es darum geht,

22:54.420 --> 22:56.100
eben diese IO-Exception auch wieder einzufangen.

22:57.140 --> 22:59.960
Und jetzt sehen Sie hier schon dieses neue Wort throws.

23:01.300 --> 23:05.760
throws sagt, in foo kann es potenziell passieren, dass eine IO

23:05.760 --> 23:06.940
-Exception ausgelöst wird.

23:07.040 --> 23:08.280
Das, was hinter throws steht.

23:10.060 --> 23:12.420
Und das heißt, der Aufrufer muss damit umgehen.

23:13.120 --> 23:16.100
Und der Aufrufer muss damit umgehen, heißt zwei Möglichkeiten.

23:16.100 --> 23:19.860
Möglichkeit 1 ist, er reicht sie selber weiter wie eine heiße

23:19.860 --> 23:20.300
Kartoffel.

23:20.920 --> 23:23.040
Das heißt, er sagt selber throws IO-Exception.

23:23.160 --> 23:25.280
Das heißt, foo kann eine Exception auslösen.

23:25.720 --> 23:28.000
Das sehe ich an dem, was hier in der Signatur von foo steht.

23:28.120 --> 23:30.040
Nämlich IO-Exception throws.

23:30.480 --> 23:33.980
Also muss ich das selber auch wieder angeben, weil indirekt durch den

23:33.980 --> 23:38.780
Aufruf von foo kann auch in bar eine IO-Exception geworfen werden.

23:39.220 --> 23:42.020
Auch wenn hier selber in bar schon nichts mehr von throw steht.

23:42.300 --> 23:45.120
Aber wie gesagt, durch den Aufruf, und hier kann es ja passieren, hier

23:45.120 --> 23:46.920
steht das throw, muss ich die weiterreichen.

23:47.260 --> 23:49.960
Die andere Alternative, wie man mit Exceptions umgeht, kennen Sie

23:49.960 --> 23:50.140
schon.

23:50.200 --> 23:53.220
Ich schreibe den Catchblock und mache das Ganze mit einem Try-Trimmer

23:53.220 --> 23:53.900
rum und dann Catch.

23:54.260 --> 23:55.160
Und das sehen Sie hier bei bus.

23:55.960 --> 23:57.800
Bus ruft bar auf, also das da.

23:58.400 --> 24:00.260
Bar sagt wieder throws IO-Exception.

24:00.440 --> 24:03.220
Jetzt könnte ich natürlich entweder auch bei bus mit throws IO

24:03.220 --> 24:05.000
-Exception das wieder an den Aufrufer weitergeben.

24:05.720 --> 24:08.760
Oder aber ich sage jetzt, nee, jetzt hier an der Stelle habe ich genug

24:08.760 --> 24:09.320
Informationen.

24:09.320 --> 24:11.000
Jetzt weiß ich, wie ich damit umgehe.

24:11.800 --> 24:15.980
Und dann mache ich eben einen Try-Catchblock und sammle jetzt hier die

24:15.980 --> 24:16.920
IO -Exception ein.

24:17.360 --> 24:21.180
Und das hat logischerweise auch zur Folge, dass ich hier natürlich

24:21.180 --> 24:23.780
kein throws mehr brauche, weil ich habe es ja hier mit Catch schon

24:23.780 --> 24:24.300
abgefangen.

24:24.780 --> 24:25.980
Also immer entweder oder.

24:26.160 --> 24:27.760
Also Sie lösen eine Exception aus.

24:28.440 --> 24:31.060
Entweder schreiben Sie jetzt mit throws das Ganze in Ihre

24:31.060 --> 24:33.700
Methodensignatur rein und signalisieren dem Aufrufer, diese Exception

24:33.700 --> 24:35.540
kann kommen und die ist auch nicht irgendwie abgefangen.

24:36.060 --> 24:39.160
Oder aber Sie behandeln sie mit Try-Catch.

24:40.120 --> 24:42.060
Und dann brauchen Sie aber logischerweise nicht mehr mit throws

24:42.060 --> 24:42.780
deklarieren.

24:44.900 --> 24:47.560
So und das zeigt jetzt nochmal den Kontrollfluss, wie er passiert.

24:47.640 --> 24:51.500
Wenn jetzt hier die IO-Exception ausgelöst wird, beende ich hier,

24:52.420 --> 24:54.420
springe sofort zum Aufrufer zurück, weil hier gibt es keinen

24:54.420 --> 24:54.920
Catchblock.

24:55.880 --> 24:57.200
Dasselbe passiert hier auch.

24:57.340 --> 25:00.220
Ich muss sofort, also das wird gar nicht mehr ausgeführt, das Ganze

25:00.220 --> 25:02.180
geht wieder zum Aufrufer zurück bei bar.

25:02.180 --> 25:06.060
Bei bar geht es jetzt dann weiter gleich zum Catchblock und hier fange

25:06.060 --> 25:06.460
ich es dann ab.

25:09.560 --> 25:11.640
So, das ist auch nochmal das, was ich gerade gesagt habe.

25:13.480 --> 25:16.740
Der Ausspruch heißt bei der Exception Catch or Specify.

25:17.260 --> 25:20.040
Entweder schreiben Sie halt ein Catchblock Ausnahme Exception-Händler

25:20.040 --> 25:22.440
dazu oder Sie spezifizieren es mit throws.

25:22.620 --> 25:23.520
Das ist das, was hier steht.

25:24.340 --> 25:27.200
Wie ich gesagt hatte, nicht behandelnde Exceptions müssen in

25:27.200 --> 25:30.220
Methodenkopf oder in der Signatur, Methodenkopf ist das Synonym für

25:30.220 --> 25:33.100
Signatur, das muss nur deklariert werden und das passiert eben durch

25:33.100 --> 25:34.380
dieses Wort throws.

25:35.400 --> 25:38.360
Und das heißt halt, der Aufrufer muss sich jetzt um die Behandlung der

25:38.360 --> 25:40.360
Exception kümmern und wie wir in unserem Beispiel gesehen haben, der

25:40.360 --> 25:43.020
Aufrufer kann selber auch wieder sagen, kümmere ich mich nicht drum,

25:43.220 --> 25:45.160
aber das heißt, ich muss mit throws es wieder weitergeben.

25:47.720 --> 25:49.920
So, es gibt ein paar Ausnahmen von dieser Regel.

25:50.780 --> 25:52.760
Und das ist einmal die Runtime Exception.

25:54.460 --> 25:58.020
Das ist quasi, wenn man so will, so ein Hack in Java, aber wo man halt

25:58.020 --> 26:01.880
gesagt hat, naja, eine Runtime Exception, das ist was, was orthogonal

26:01.880 --> 26:05.740
an vielen Stellen passieren kann, da verlange ich nicht, dass es

26:05.740 --> 26:07.460
überall mit throws deklariert wird.

26:07.780 --> 26:11.000
Und dasselbe gilt für einen Error, der kann auch quasi immer an allen

26:11.000 --> 26:15.080
Stellen aufpassen und bevor man jetzt jedes Mal bei throws dann einen

26:15.080 --> 26:16.480
Error dabei schreibt, darf man das letzte Mal weg.

26:17.260 --> 26:20.380
Diejenigen von Ihnen, die C-Sharp kennen, und ich weiß ja, das sind

26:20.380 --> 26:23.300
einige, da ist die Regel anders, da gibt es nicht dieses Catch or

26:23.300 --> 26:23.860
Specify.

26:23.860 --> 26:28.300
In C-Sharp hat man mal auch nach einer langen Diskussion gesagt, nee,

26:28.380 --> 26:32.600
das mit diesem throws deklarieren im Methodenkopf, in der Signatur,

26:33.080 --> 26:35.880
das ist zu nervig und da hat man es komplett weggelassen.

26:36.100 --> 26:39.740
Also in C-Sharp gilt nicht Catch or Specify, da können Sie catchen

26:39.740 --> 26:42.060
oder Sie brauchen es nicht spezifizieren, da muss sich trotzdem der

26:42.060 --> 26:42.760
Aufrufer umkümmern.

26:42.840 --> 26:45.560
Das heißt, die Semantik ist eigentlich dieselbe wie in Java, nur dass

26:45.560 --> 26:47.100
Sie eben das throws nicht hinschreiben müssen.

26:47.960 --> 26:49.360
Jetzt ist das vielleicht eine Geschmackssache.

26:50.960 --> 26:53.480
Mein Geschmack ist der, dass es mir in Java besser gefällt.

26:54.260 --> 26:56.960
Wenn ich was anprogrammiere, will ich gerne wissen, welche Exceptions

26:56.960 --> 26:57.960
können da auftauchen.

26:58.460 --> 27:02.120
Und ich habe halt als Java-Programmierer im Hinterkopf, okay, Error

27:02.120 --> 27:04.760
und Randheim-Exception können auch noch passieren, auch wenn sie nicht

27:05.760 --> 27:06.400
deklariert wurde.

27:06.760 --> 27:10.720
Aber wie gesagt, das ist eher eine Geschmackssache und es gab auch,

27:10.720 --> 27:13.420
wie gesagt, vehemente Diskussionen damals bei der Definition der C

27:13.420 --> 27:15.360
-Sharp -Sprache, die ja wie gesagt jünger ist als Java.

27:15.940 --> 27:18.140
Und da hat man auch bewusst sich entschieden, es anders zu machen.

27:18.880 --> 27:21.180
Aber an sich, wie gesagt, auch was hier steht, alleine schon aus

27:21.180 --> 27:24.420
Dokumentationsgründen ist es eigentlich sinnvoll, bei throws immer

27:24.420 --> 27:25.480
möglichst viel anzugeben.

27:25.840 --> 27:28.280
Nur wie gesagt, jetzt vielleicht nicht die Error, weil das kann halt

27:28.280 --> 27:28.820
immer auftauchen.

27:29.060 --> 27:31.200
Das ist eigentlich das, was ich auch schon auf der Tonspur gesagt

27:31.200 --> 27:31.480
habe.

27:34.040 --> 27:38.420
Error zeigt ernsthafte Probleme an in der Ablaufumgebung, die Sie in

27:38.420 --> 27:39.860
dem Sinne nicht mehr korrigieren können.

27:40.360 --> 27:43.380
Weil der Programmierer der Java Virtual Machine Fehler gemacht hat,

27:43.420 --> 27:45.720
das können Sie auch nicht on the fly fixen, weil vielleicht der

27:45.720 --> 27:49.200
Compiler Code erzeugt hat, der so keinen Sinn macht oder komplett

27:49.200 --> 27:51.160
ungültiger Bytecode schon ist.

27:51.880 --> 27:53.440
Das sind also Dinge, die können Sie nicht mehr als

27:53.440 --> 27:55.000
Anwendungsprogrammierer on the fly ändern.

27:55.180 --> 27:56.500
Das ist dafür das Error vorgesehen.

27:57.320 --> 28:01.060
Und Runtime Exceptions sind Programmierfehler, die aber erst zur

28:01.060 --> 28:02.960
Laufzeit festgestellt werden.

28:03.580 --> 28:06.200
Das mit dem Können muss man mal vielleicht ein bisschen ungenau sehen,

28:06.740 --> 28:08.480
weil man könnte vielleicht sagen, wenn Sie mehr getestet hatten,

28:08.560 --> 28:10.260
hätten Sie es auch schon zur Testzeit feststellen können.

28:10.260 --> 28:12.580
Das hängt ein bisschen davon ab, wie viel gut Sie getestet haben.

28:13.260 --> 28:15.960
Aber wie gesagt, wo man sagt, im Prinzip werden die zur Laufzeit erst

28:15.960 --> 28:19.960
festgestellt und man kann jetzt eben nicht sinnvoll unbedingt

28:19.960 --> 28:22.000
weitermachen, weil Sie vielleicht eben einen Null-Pointer bekommen

28:22.000 --> 28:24.020
haben, wo Sie keinen brauchen können.

28:25.380 --> 28:31.520
Aber das ist nochmal was anderes, wie wenn man sagt, ich hab jetzt

28:31.520 --> 28:34.880
eine Datei nicht öffnen können, dann kann man vielleicht noch sinnvoll

28:34.880 --> 28:35.760
was machen an der Stelle.

28:36.780 --> 28:39.920
Für was sollte man jetzt Catchblöcke schreiben?

28:40.500 --> 28:41.180
Für Error?

28:41.820 --> 28:42.100
Nö.

28:42.700 --> 28:43.880
Ist per Definition nicht sinnvoll.

28:44.360 --> 28:47.080
Wenn die Java Virtual Machine falsch ist oder der Compiler Mist gebaut

28:47.080 --> 28:48.740
hat, können Sie eh nichts mehr sinnvoll machen.

28:49.340 --> 28:52.860
Einfach nur laufen lassen, dann gibt es eine Fehlermeldung auf der

28:52.860 --> 28:54.900
Konsole und damit muss sich irgendeiner rumschlagen.

28:56.240 --> 28:58.780
Ob Sie das auch in schöne Fenster verpacken, ist vollkommen egal.

29:00.180 --> 29:02.320
Dann gibt es die Exception-Klasse selber.

29:02.440 --> 29:04.860
Das könnte man theoretisch fangen.

29:05.480 --> 29:07.380
Man könnte natürlich CatchException schreiben.

29:07.880 --> 29:09.840
Ist aber wirklich super schlechter Stil.

29:10.400 --> 29:11.780
Weil das ist so allgemein.

29:13.060 --> 29:15.740
Da haben Sie auch nicht genug Kontextinformationen, außer dass Sie

29:15.740 --> 29:18.440
vielleicht sagen können, oder war ein Exception in Klammern, was auch

29:18.440 --> 29:20.520
ausgegeben wurde, wenn Sie keinen Catchblock geschrieben hätten.

29:21.960 --> 29:22.600
Können Sie auch nicht machen.

29:22.740 --> 29:23.340
Also auch nicht.

29:24.160 --> 29:25.300
Und jetzt geht es los.

29:27.500 --> 29:29.300
Unterklassen von Exception natürlich.

29:31.080 --> 29:32.560
Runtime-Exceptions und Unterklassen.

29:32.660 --> 29:37.540
Naja, im Allgemeinen kann man da eigentlich auch nichts Sinnvolles

29:37.540 --> 29:37.860
machen.

29:39.040 --> 29:41.260
Ich meine, das ist offenbar ein Fehler im Programmcode.

29:41.980 --> 29:42.980
Und was wollen Sie jetzt machen?

29:43.120 --> 29:45.340
Ich meine, ich hatte schon mal Software gehabt, die dann sagt, oh,

29:45.420 --> 29:47.080
dieser Zustand hätte nicht erreicht werden können.

29:47.180 --> 29:48.160
Dann sage ich, danke für die Info.

29:48.420 --> 29:49.720
Was soll ich jetzt als Anwender machen?

29:50.900 --> 29:51.760
Hilft mir ja auch nicht.

29:52.040 --> 29:54.920
Das heißt mit anderen Worten, das ist schon sinnvoll, so eine

29:54.920 --> 29:56.100
Exception auszulösen.

29:56.100 --> 29:59.920
Aber eigentlich sollte dann irgendein Programmierer sich drum kümmern.

30:00.260 --> 30:03.020
Sei es derjenige, der offenbar den Bug verbrochen hat oder irgendein

30:03.020 --> 30:05.100
anderer, der sich um die Qualitätssicherung kümmert.

30:05.420 --> 30:08.440
Aber der User kann auch an der Stelle nicht sinnvoll eingebunden

30:08.440 --> 30:08.700
werden.

30:08.800 --> 30:12.520
Und das heißt mit anderen Worten, das mit Catch abzufangen macht nicht

30:12.520 --> 30:13.800
mehr eigentlich allzu viel Sinn.

30:14.300 --> 30:17.620
Weil, wie gesagt, wenn Sie es laufen lassen, also mit Throws bis zum

30:17.620 --> 30:19.460
Ende, dass das Programm abgebrochen wird, dann wird auch die

30:19.460 --> 30:20.300
Fehlermeldung ausgegeben.

30:20.380 --> 30:22.640
Der Stacktray ist automatisch ausgegeben von der JVM.

30:22.640 --> 30:26.560
Also insofern, die Ursache wird angegeben und dann muss sich eben

30:26.560 --> 30:29.720
jemand drum kümmern, der sich den Programmcode ändern kann und den Bug

30:29.720 --> 30:30.440
korrigieren kann.

30:31.180 --> 30:34.440
Natürlich kann man sich überlegen, dass man sagt, ich habe ein

30:34.440 --> 30:37.120
besonders schlaues System, was halt eben noch zur Laufzeit

30:37.120 --> 30:40.580
mitmonitort, wie viele Fehler waren und deswegen möchte ich das noch

30:40.580 --> 30:41.900
in ein Log-System eintragen.

30:42.300 --> 30:45.240
Kann man sich alles überlegen, aber wenn man ehrlich ist, das ist

30:45.240 --> 30:45.920
alles nicht sinnvoll.

30:46.000 --> 30:48.140
Sie sollten in erster Linie versuchen, Fehler, die aufgetaucht sind,

30:48.140 --> 30:51.480
zu korrigieren und nicht anders zur Laufzeit noch versuchen zu

30:51.480 --> 30:51.880
behandeln.

30:52.400 --> 30:54.400
Dann sind wir an der Stelle, wo wir sagen, okay, jetzt brauche ich

30:54.400 --> 30:55.100
eigene Exceptions.

30:55.240 --> 30:58.060
Das sind Dinge, wo Sie speziell für Ihr Programm sagen, ich möchte

30:58.060 --> 31:00.900
jetzt eine eigene Exception-Unterklasse haben und eine besondere Art

31:00.900 --> 31:03.240
von Fehlerzustand, die spezifisch ist für meine Anwendung, zu

31:03.240 --> 31:03.840
signalisieren.

31:04.260 --> 31:07.180
Und das machen Sie eben, indem Sie entweder von Exception ableiten,

31:07.480 --> 31:11.780
das ist das, wenn irgendwas korrigierbares ist, wie sagst du, die

31:11.780 --> 31:15.480
Laufzeitumgebung, also das Dateisystem, irgendeine Ressource, die

31:15.480 --> 31:17.480
nicht zur Verfügung steht, aber alles, was behandelbar ist, also nicht

31:17.480 --> 31:18.040
die Errorsachen.

31:19.600 --> 31:23.220
Oder wenn ein spezieller Programmierfehler aufgetaucht ist, dann

31:23.220 --> 31:24.860
leiten Sie von Runtime-Exception ab.

31:26.180 --> 31:29.160
Und denken Sie dann, dass Sie immer die zwei Standard-Konstruktoren,

31:29.240 --> 31:31.360
also den mit String und den Default-Konstruktoren mit Leer

31:31.360 --> 31:31.960
implementieren.

31:32.480 --> 31:33.920
Warum den mit Leer implementieren?

31:34.020 --> 31:37.100
Naja, wenn Sie einen Konstruktor implementieren, den mit String, gibt

31:37.100 --> 31:39.000
es keinen Default-Konstruktor mehr, der wird ja dann nicht mehr

31:39.000 --> 31:39.340
generiert.

31:39.440 --> 31:40.900
Sie erinnern sich, wie das mit den Konstruktoren war.

31:40.900 --> 31:42.800
Also müssen Sie den auch dabei schreiben.

31:44.120 --> 31:46.940
So, und dann können Sie im Prinzip eine eigene Exception-Hierarchie

31:46.940 --> 31:49.240
machen, die auch weiter verfeinert durch die Unterklassenbildung.

31:49.440 --> 31:52.880
Sie erinnern sich, Vererbung ist im Prinzip Spezialisierung.

31:54.480 --> 31:59.140
Und es gibt aber von Java eben auch schon Exceptions vordefiniert.

31:59.180 --> 32:01.260
Und die brauchen Sie natürlich nicht nachprogrammieren.

32:01.320 --> 32:02.980
Die können Sie gleich auslösen, die gibt es schon.

32:03.380 --> 32:05.860
Also Sie brauchen keinen eigenen Null-Pointer-Exception.

32:05.860 --> 32:09.100
Oder Sie brauchen keine neue Exception definieren, wenn Sie

32:09.100 --> 32:11.700
feststellen, dass einer Sie mit schwachsinnigen Parametern aufgerufen

32:11.700 --> 32:11.820
hat.

32:11.900 --> 32:14.680
Da können Sie einfach ThrowNew und diese Exception-Klassen machen.

32:15.280 --> 32:19.920
Die Exceptions, wie ich eingangs motiviert hatte, dienen dazu,

32:20.760 --> 32:23.340
Fehlerzustände, Ausnahmezustände zu signalisieren.

32:24.500 --> 32:27.280
Und das machen Sie deswegen, weil wenn man ohne Exceptions versuchen

32:27.280 --> 32:29.840
würde, damit umzugehen, Sie erinnern sich an die Eingangsbeispiele mit

32:29.840 --> 32:33.040
GOTO oder dem FLAG, wird der Programmcode unter Umständen sehr, sehr

32:33.040 --> 32:36.600
komplex und lenkt von der eigentlichen Funktionalität ab, weil Sie auf

32:36.600 --> 32:40.480
einmal die Implementierung der eigentlichen Algorithmik zur Lösung des

32:40.480 --> 32:43.680
Problems vermischen mit Code, der Fehler behandelt.

32:43.740 --> 32:46.260
Und das ist halt im Sinne von Separations of Concern, also Trennung

32:46.260 --> 32:47.960
der Belange, keine gute Idee.

32:49.480 --> 32:53.180
Das heißt aber auch mit anderen Worten, Sie sollten das ganze Throws

32:53.180 --> 32:56.580
oder das ganze Exception Handling nicht nehmen für eigentlich Dinge,

32:56.700 --> 32:57.600
die regulär auftauchen.

32:57.720 --> 32:59.940
Dafür ist es nämlich auch nicht gedacht, sondern immer nur für

32:59.940 --> 33:00.680
Ausnahmezustände.

33:00.680 --> 33:05.940
Und das ist halt ein Antibeispiel, so Code möchte ich bitte nie sehen.

33:06.780 --> 33:10.480
Hier laufen Sie durch ein Array durch, und es ist vollkommen klar,

33:10.600 --> 33:13.340
irgendwann werden Sie an die Grenze des Arrays kommen, weil unendliche

33:13.340 --> 33:14.420
Arrays gibt es halt nun mal nicht.

33:15.460 --> 33:19.900
Und Sie sehen, hier gibt es keine Abbruchbedingungen, die sich darum

33:19.900 --> 33:21.560
kümmern, dass ich die Arraygrenze erreiche.

33:23.180 --> 33:26.000
Also mache ich dann hier noch ein Catch Array Index Out of Bounds

33:26.000 --> 33:28.880
Exception, weil die Exception wird irgendwann kommen, das ist klar,

33:28.960 --> 33:31.000
egal wie groß das Array ist, irgendwann werden Sie die erreicht haben

33:31.000 --> 33:33.040
mit dem Code hier.

33:33.840 --> 33:35.760
Seitdem, wie gesagt, Sie brechen wegen der Bedingungen ab, oder das

33:35.760 --> 33:36.940
muss ja nicht notwendigerweise sein.

33:37.240 --> 33:41.560
Und dann sagen Sie, quasi Standardergebnis, dieses Element Character

33:41.560 --> 33:42.340
wurde nicht gefunden.

33:43.600 --> 33:46.320
Klar, das kann man so programmieren, aber das ist voll gegen die Idee

33:46.320 --> 33:49.720
von Exceptions, weil Sie eigentlich für die normale Algorithmik auf

33:49.720 --> 33:50.820
einmal Exceptions verwenden.

33:50.920 --> 33:53.100
Und dafür sind wie gesagt Exceptions nicht gedacht, es geht darum,

33:53.960 --> 33:56.420
Ausnahmezustände zu machen, und dass Sie nochmal irgendwann an die

33:56.420 --> 33:58.760
Grenze von einem Array kommen, wenn Sie darüber iterieren, das ist

33:58.760 --> 34:01.480
keine Ausnahme, das ist normal, da müssen Sie die Abbruchbedingungen

34:01.480 --> 34:06.640
reinkodieren, also hier müsste halt eben drinstehen und i kleiner

34:06.640 --> 34:10.300
Array.length, aber eben nicht das ganze über eine Exception abfangen.

34:10.500 --> 34:13.340
Das geht, klar, das kompiliert auch, das macht auch das, was es soll,

34:13.860 --> 34:16.500
aber das ist halt Missbrauch dieser Exception-Idee.

34:16.900 --> 34:18.180
Und warum ist das böse?

34:19.360 --> 34:21.500
Sie schreiben den Code nicht für den Compiler, sondern für den

34:21.500 --> 34:23.420
nächsten Menschen, der erlesen muss, Sie haben es schon oft genug von

34:23.420 --> 34:23.840
mir gehört.

34:24.740 --> 34:27.240
Und das ist halt einfach für die Verständlichkeit schlecht, weil die

34:27.240 --> 34:29.500
Grundannahme beim Lesen von einer Exception ist halt, das ist ein

34:29.500 --> 34:32.780
Ausnahmezustand, das ist nicht Teil der regulären Algorithmik.

34:33.800 --> 34:37.560
Und deswegen auch mal gleich so ein paar Faustregeln im Sinne von, was

34:37.560 --> 34:40.000
sieht man, wie es aber nicht gemacht werden sollte.

34:41.280 --> 34:44.020
Also, natürlich geht es, dass man den Dreiblock um das gesamte

34:44.020 --> 34:44.860
Programm schreibt.

34:45.600 --> 34:48.500
Und sagt, okay, irgendwo kann ja mal eine Exception kommen, dann fange

34:48.500 --> 34:50.220
ich die jetzt an der Stelle auch großartig ab.

34:51.240 --> 34:52.820
Das ist nicht so eine schlaue Idee.

34:53.380 --> 34:53.880
Warum nicht?

34:54.000 --> 34:57.900
Naja, weil Sie ja hier in der Regel, wenn das das gesamte Programm

34:57.900 --> 35:01.080
ist, eigentlich gar nicht mehr so genau wissen, an welcher Stelle sind

35:01.080 --> 35:02.560
jetzt diese Exceptions ausgelöst worden.

35:02.640 --> 35:04.700
Natürlich können Sie jetzt sagen, ich leite mir so eine

35:04.700 --> 35:08.200
superspezifische Unterklasse von Exception ab, die dann eindeutig ist,

35:08.280 --> 35:10.140
und dann kann ich es auch hier eindeutig identifizieren.

35:10.580 --> 35:15.280
So, ja, dann haben Sie aber extrem viele Unterklassen, wie Datei.not

35:15.280 --> 35:18.620
.found.exception an Stelle 1, Datei.not.found.exception an Stelle 2,

35:18.620 --> 35:20.620
Datei.not.found.exception an Stelle N.

35:20.980 --> 35:22.720
Das ist irgendwie blöd, ja, also sehen Sie schon.

35:23.180 --> 35:24.620
So, das heißt, das ist zu generisch.

35:25.260 --> 35:28.920
Sie müssen versuchen, schon diesen drei Catchblock möglichst eng zu

35:28.920 --> 35:32.660
fassen, um einfach dann auch spezifisch zu wissen oder spezifisch

35:32.660 --> 35:35.500
sicherzustellen, dass die ausgelöste Exception wirklich eine sehr

35:35.500 --> 35:36.520
spezielle Semantik hat.

35:36.580 --> 35:39.160
Nämlich an der Stelle, wo sie ausgelöst wurde, können Sie relativ klar

35:39.160 --> 35:40.580
sagen, das war offenbar der Grund.

35:40.940 --> 35:42.500
Weil sonst können Sie die Exception in der Regel auch nicht sinnvoll

35:42.500 --> 35:42.900
behandeln.

35:44.880 --> 35:47.180
So, also das ist... schlecht.

35:47.180 --> 35:50.320
So, dann, was man auch hin und wieder mal sieht, so...

35:50.820 --> 35:52.760
Ich fange die Exception ab, mache aber dann nichts.

35:54.040 --> 35:55.220
Klar, kann man auch hinschreiben.

35:55.340 --> 35:56.940
Motzt auch kein Compiler, aber ich.

35:57.560 --> 35:58.180
Und zwar warum?

35:58.620 --> 36:02.060
Naja, weil im Prinzip Sie ja hier das unterdrücken.

36:03.340 --> 36:05.960
Das System merkt, hier ist irgendwas schief gelaufen.

36:06.020 --> 36:07.140
Ich habe einen Fehlerzustand.

36:07.900 --> 36:10.880
Und Sie würgen das ab und sagen, ja, mach weiter, als ob es normal

36:10.880 --> 36:11.080
wäre.

36:11.300 --> 36:12.440
Hiernach kannst du wieder weitermachen.

36:12.500 --> 36:13.980
Ist vollkommen egal, ob das ein Fehlerzustand war.

36:14.220 --> 36:17.480
Dann war es entweder kein richtiger Fehlerzustand oder aber, noch

36:17.480 --> 36:20.020
schlimmer, Sie schleppen einen Fehlerzustand weiter mit dem Programm,

36:21.340 --> 36:23.740
der ja eben ein Fehlerzustand ist und das gehört sich auch nicht.

36:24.040 --> 36:25.420
Also das soll man auch nicht machen.

36:27.620 --> 36:31.640
So, dann, das was man auch manchmal sieht und was natürlich auch geht,

36:32.300 --> 36:34.480
dass man sagt, ah, mir vollkommen egal diese ganzen Kack

36:34.480 --> 36:36.220
-Unterklassifikationen von Exception.

36:36.400 --> 36:37.360
Ich fange einfach Exception.

36:37.820 --> 36:39.340
Da gilt aber im Prinzip dasselbe wie eben.

36:39.440 --> 36:40.780
Das ist viel zu allgemein.

36:42.020 --> 36:43.760
Das hat keine besonders tolle Semantik.

36:43.760 --> 36:46.360
Außer, dass Sie wissen, irgendwo ist irgendwas passiert, wissen Sie

36:46.360 --> 36:47.200
eigentlich nichts an der Stelle.

36:47.920 --> 36:48.640
Auch nicht gut.

36:49.100 --> 36:53.700
So, dann könnte man das Ganze noch besser treiben und sagen, throwable

36:53.700 --> 36:54.140
fange ich ab.

36:54.180 --> 36:55.580
Das ist ja die Oberklasse von Exception.

36:56.140 --> 36:56.760
Geht auch.

36:57.040 --> 36:59.000
Aber wie gesagt, das ist natürlich ein absolutes No-Go.

36:59.820 --> 37:02.380
Und wie gesagt, Errors können Sie ja auch nicht maskieren.

37:02.480 --> 37:03.780
Also vergessen Sie es, bringt gar nichts.

37:05.260 --> 37:08.400
Wie man es stattdessen machen sollte, und das ist vielleicht unter dem

37:08.400 --> 37:12.900
Schlagwort, was einige kennen, fail fast bekannt.

37:12.900 --> 37:15.200
Fail fast, also schnelles Scheitern.

37:15.280 --> 37:17.380
Klingt ja irgendwie erstmal negativ, weil Scheitern ist schlecht.

37:17.660 --> 37:19.500
Und schnell scheitern ist irgendwie noch schlechter als normales

37:19.500 --> 37:19.840
Scheitern.

37:20.840 --> 37:25.380
Trotzdem aber die Idee ist, wenn ein Fehlerzustand auftaucht, versuche

37:25.380 --> 37:30.360
ihn möglichst einzugrenzen und versuche möglichst schnell darauf zu

37:30.360 --> 37:30.840
reagieren.

37:30.920 --> 37:33.540
Und deswegen eben nicht so try-catch-gesamtes Programm, weil da können

37:33.540 --> 37:34.780
Sie nicht mehr spezifisch reagieren.

37:35.480 --> 37:39.140
Und selbst wenn Sie den Fehler nicht sinnvoll mehr behandeln können,

37:39.220 --> 37:42.140
im Sinne von irgendeiner User-Interaktion oder einer retry-Operation

37:42.140 --> 37:45.300
oder sowas, alleine für das Debugging, das heißt also für die

37:45.300 --> 37:50.460
Fehlersuche in Ihrem Programm, hilft es Ihnen enorm, den Bereich

37:50.460 --> 37:53.020
einzugrenzen, wo in Ihrem Code der Fehler liegt.

37:53.340 --> 37:55.380
Und deswegen ist das schon sinnvoll mit diesem fail fast.

37:55.760 --> 37:58.540
So und jetzt gibt es im Prinzip ein bisschen zugegebenermaßen

37:58.540 --> 38:00.700
Diskussionen um dieses Stichwort defensive Programmierung.

38:01.560 --> 38:06.260
Defensive Programmierung heißt, Sie als Implementierer,

38:06.300 --> 38:09.760
Implementiererin einer Methode, versuchen möglichst viele

38:09.760 --> 38:13.080
Fehlerzustände, die von außen beim Aufruf reinkommen in Ihre Methode,

38:13.180 --> 38:14.740
in Ihren Code abzufangen.

38:15.540 --> 38:17.920
Und das heißt, Sie prüfen ab, zum Beispiel die Parameter, ob die

38:17.920 --> 38:22.220
stimmen sich prüfen ab, ob Attribute sinnvolle Werte haben, der Klasse

38:22.220 --> 38:22.700
und so weiter.

38:23.300 --> 38:26.660
Das kann man machen, das führt aber zu relativ viel Kot, hat aber den

38:26.660 --> 38:32.440
Vorteil natürlich, wenn man streng defensiv programmiert, dass man

38:32.440 --> 38:34.600
natürlich dafür sorgt, dass Fehlerzustände offenbar sehr schnell

38:34.600 --> 38:38.000
auffallen, nämlich hoffentlich schon beim Aufruf der nächsten Methode.

38:39.280 --> 38:42.320
Es gibt auch durchaus Anhänger davon, vom defensiven Programmieren.

38:42.400 --> 38:44.200
Es gibt aber auch Feinde, sage ich auch ganz offen.

38:44.280 --> 38:46.420
Das ist so eine Stilfrage, die vielleicht nicht ganz so eindeutig ist,

38:46.440 --> 38:48.100
wie die anderen Sachen, die ich Ihnen erzählt habe.

38:48.680 --> 38:50.860
Und zwar deswegen, weil es natürlich den Kot auch aufbläht.

38:51.180 --> 38:54.060
Wenn Sie für jede Methode, für jeden Parameter abprüfen, ist er

38:54.060 --> 38:54.480
gültig.

38:54.840 --> 38:58.600
Jedes Mal neu abprüfen, sind die Variablen, die Attribute eigentlich

38:58.600 --> 38:59.700
in einem vernünftigen Zustand.

39:00.640 --> 39:04.900
Dann ist das so, Sie haben sehr viel Programmkot, Sie haben auch einen

39:04.900 --> 39:06.440
gewissen Overhead, natürlich zur Laufzeit.

39:07.140 --> 39:10.360
Und das Konzept, wie man beide Vorteile wieder zusammenbringt, die vom

39:10.360 --> 39:14.180
defensiven Programmieren, schnelles Finden von Fehlerzuständen und auf

39:14.180 --> 39:16.980
der anderen Seite aber eben nicht zu schwergewichtige Sachen, das

39:16.980 --> 39:22.040
heißt Design by Contract, das ist ein Konzept von Bertrand Meyer, also

39:22.040 --> 39:24.440
von dem Mann, der das Buch Object-Oriented Software Construction

39:24.440 --> 39:26.880
geschrieben hat, den ich Ihnen letztes Mal genannt hatte.

39:26.880 --> 39:29.500
Das kommt bei der Vorlesung Programmierparadigmen dran.

39:29.680 --> 39:31.620
Also jetzt nicht traurig sein, das ist ja auch Pflichtprogramm im

39:31.620 --> 39:31.880
Bachelor.

39:32.420 --> 39:34.220
Aber wie gesagt, da haben Sie noch ein paar Semester mit Zeit.

39:35.200 --> 39:37.600
Weil das jetzt den Rahmen dieser Anfängervorlesung sprengen würde.

39:37.980 --> 39:40.480
An der Stelle nur den Hinweis, also defensive Programmierung heißt,

39:41.260 --> 39:43.700
möglichst viel abfangen als Implementierer einer Klasse.

39:46.240 --> 39:48.080
Und das ist gut und schlecht zugleich.

39:48.280 --> 39:51.260
Und wie man diesen Kompromiss quasi findet, da zwischen viel

39:51.260 --> 39:53.660
Programmtexten auflösen und auf der anderen Seite aber schlanken Kot,

39:53.940 --> 39:55.780
das heißt Design by Contract, kommt aber später dran.

39:58.640 --> 40:01.960
Hier sieht man auch ein schlechtes Beispiel, wie man es eben nicht

40:01.960 --> 40:04.420
machen sollte, was auch so ein bisschen dieser Logik widerspricht.

40:05.100 --> 40:09.640
Und zwar ist das in der Java-Util-Klasse Properties drin, die es

40:09.640 --> 40:11.100
leider so implementiert ist.

40:11.200 --> 40:13.640
Das heißt, auch bei Java ist nicht alles brillant gelöst.

40:14.940 --> 40:19.520
Und zwar ist es so, bei Properties, das ist im Prinzip eine ganz

40:19.520 --> 40:24.260
einfach gesprochen Abbildung zwischen einem Schlüssel, Key, und einem

40:24.260 --> 40:25.840
Wert in dem zugeordnetes Value.

40:26.540 --> 40:31.720
Und es gibt an irgendeiner Stelle auch die Möglichkeit, einen Output

40:31.720 --> 40:32.840
-Stream zu erzeugen.

40:33.320 --> 40:36.280
Und dann müssen aber tatsächlich die Values alle Strings sein, weil

40:36.280 --> 40:37.500
sonst klappt das an der Stelle nicht.

40:38.060 --> 40:40.260
Auch ein bisschen idiotisch, weil man kann ja mit two String jedes

40:40.260 --> 40:41.680
Objekt umbauen, aber es ist so.

40:42.560 --> 40:45.700
Und das heißt mit anderen Worten, wenn Sie jetzt hier was einfügen als

40:45.700 --> 40:48.880
Objekt -Value, was kein String ist, knallt es hier nicht beim Put,

40:49.200 --> 40:50.460
sondern erst hier beim Store.

40:51.380 --> 40:54.500
Und das ist natürlich irgendwie schlecht, weil bloß, falls beim Store

40:54.500 --> 40:56.520
knallt, wissen Sie immer noch nicht, an welcher Stelle beim Put ist

40:56.520 --> 40:58.640
eigentlich das Nicht-String-Element eingefügt worden.

40:59.020 --> 41:00.900
Und das heißt, Sie haben eigentlich für die Fehlersuche jetzt nicht

41:00.900 --> 41:02.780
allzu viel Hilfe durch die Konstruktion hier.

41:03.140 --> 41:07.380
Und es wäre natürlich besser, schon hier an der Stelle das Ganze

41:07.380 --> 41:07.560
abzufangen.

41:08.100 --> 41:10.400
Jetzt können Sie sagen, ja, aber vielleicht will ich ja so Key-Value

41:10.400 --> 41:12.380
-Pairs haben, wo der Value nicht vom Typ String ist.

41:12.740 --> 41:15.120
Ja, aber dann machen Sie bitte eine eigene Klasse, und zwar eine

41:15.120 --> 41:16.580
Klasse ohne dieses bescheute Store.

41:17.220 --> 41:19.540
Also das wäre die gute Lösung gewesen, hat man aber nicht gemacht.

41:20.260 --> 41:22.100
Dann haben Sie es jetzt schon fast geschafft.

41:22.820 --> 41:24.700
Das löst jetzt nochmal hier die Zusammenfassung.

41:25.980 --> 41:30.560
Wir haben Ausnahmen, die heißen Exceptions, die werden ausgelöst mit

41:30.560 --> 41:34.160
dem Wort Throw, und dann New, dann der Exception-Klassennamen.

41:35.060 --> 41:37.700
Sie werden abgefangen in einem Try-Catch-Block.

41:37.820 --> 41:40.480
Try ist die Stelle, wo es auftauchen kann, Catch ist der

41:40.480 --> 41:41.880
Fehlerbehandlungscode.

41:42.320 --> 41:45.340
Oder Sie müssen in Java deklariert werden, bis auf die wenigen

41:45.340 --> 41:48.080
Ausnahmen, die wir genannt haben, in der Methodensignatur mit dem Wort

41:48.080 --> 41:48.900
Throws.

41:50.120 --> 41:53.120
Und diese Ausnahmen sind eben die Ausnahme und eben nicht Teil der

41:53.120 --> 41:54.020
regulären Algorithmik.

41:54.120 --> 41:55.420
Das wäre ein Missbrauch des ganzen Konstrukts.

41:56.260 --> 41:58.880
Und es soll eben trennen zwischen der Algorithmik, also der

41:58.880 --> 42:00.340
Programmlogik, und der Fehlerbehandlung.

42:01.180 --> 42:04.320
Und bei der Anwendung bitte immer so früh wie möglich versuchen,

42:04.380 --> 42:05.560
Exceptions einzufangen.

42:08.220 --> 42:11.960
Und im Prinzip schauen, ob man halt eben mit Dingen, die wir doch

42:11.960 --> 42:14.460
später kennenlernen, mit Assert, das Versuch schon ein bisschen früher

42:14.460 --> 42:14.880
zu finden.

42:14.880 --> 42:16.960
Assert geht dann auch in Richtung schon Design-By-Contract.

42:19.400 --> 42:25.460
Die Leute, die das nachlesen wollen, finden das im Kapitel 10 von

42:25.460 --> 42:29.880
unserem Anfängerbuch, wo auch Exceptions und Errors behandelt werden.

42:32.340 --> 42:37.500
So, dann wären wir jetzt an der Stelle, wo ich eigentlich mit der

42:37.500 --> 42:41.100
nächsten Vorlesung anfangen würde, nämlich Interfaces und so weiter.

42:41.100 --> 42:44.060
Aber das würde ich eh nicht mehr ganz durchbringen und das über die

42:44.060 --> 42:46.520
Weihnachtsferien liegen zu lassen, wo sie noch Silvester haben und wer

42:46.520 --> 42:48.080
weiß noch was für geistige Reboots.

42:48.560 --> 42:50.460
Deswegen machen wir jetzt die Weihnachtsvorlesung.

42:51.840 --> 42:52.200
Genau.

42:52.960 --> 42:53.960
Jetzt haben wir nicht alle weglaufen.

42:54.580 --> 42:55.720
Dafür war das zu viel Arbeit.

42:57.620 --> 43:00.600
So, und zwar, auch ich habe Ihnen ein Weihnachtsgeschenk mitgebracht.

43:00.680 --> 43:02.380
Sie haben mir das gar nicht zugetraut, ich weiß.

43:03.580 --> 43:05.520
Und zwar ist das ein Lehrerkarton.

43:05.620 --> 43:08.220
Nein, es ist die Intercal-Programmiersprache.

43:08.220 --> 43:11.340
Wer hat schon mal was von Intercal gehört vor zwei Minuten?

43:12.600 --> 43:13.060
Keiner?

43:13.540 --> 43:13.720
Doch.

43:14.420 --> 43:14.880
Sehr gut.

43:15.440 --> 43:16.880
Bonus schon mal gleich für den Übungsblatt.

43:17.100 --> 43:17.920
Intercal schon mal gehört.

43:18.040 --> 43:18.500
Großartig.

43:18.900 --> 43:20.320
Aber für die meisten ist es neu.

43:21.400 --> 43:26.040
Intercal ist absichtlich entworfen worden als eine Programmiersprache

43:26.040 --> 43:26.600
für Anfänger.

43:27.440 --> 43:28.700
Programmieren, lernen, schwer gemacht.

43:30.340 --> 43:31.420
Was ist Intercal?

43:31.420 --> 43:36.160
Also Intercal ist logischerweise naheliegenderweise das Akronym für

43:36.160 --> 43:38.600
Compiler Language with Now Pronounceable Acronym.

43:40.320 --> 43:44.280
Es soll eine sehr einfache Programmiersprache sein, wobei Sie sofort

43:44.280 --> 43:46.760
den Unterschied merken zwischen einfacher Definition der

43:46.760 --> 43:49.880
Programmiersprache und einfachem Schreiben von Programmen, was nicht

43:49.880 --> 43:50.460
dasselbe ist.

43:51.340 --> 43:52.960
Sie ist entwickelt worden am 26.

43:53.360 --> 43:56.740
Mai 1972 in der Princeton University, genauer gesagt am Vormittag, in

43:56.740 --> 43:57.520
relativ frühen Stunden.

43:58.340 --> 44:01.620
Und an der exakten Zeitangabe erkennen Sie, allzu viel Zeit ist wohl

44:01.620 --> 44:03.640
auch nicht draufgegangen, diese Programmiersprache zu verwenden.

44:05.540 --> 44:08.360
Die Hauptmotivation war, dass man wirklich keine Ähnlichkeit zu den

44:08.360 --> 44:09.220
Programmiersprachen hatte.

44:09.300 --> 44:12.420
Jetzt würden Sie sagen, 1972 gab es da schon Programmiersprachen und

44:12.420 --> 44:13.860
die bittere Antwort ist, Hunderte gab es schon.

44:13.980 --> 44:16.200
Also das war auch damals nicht so einfach, heute ist es natürlich noch

44:16.200 --> 44:16.680
schwerer.

44:17.840 --> 44:20.340
Und wenn Sie jetzt wirklich noch Ähnlichkeiten finden zu anderen

44:20.340 --> 44:21.940
Programmiersprachen, das ist wirklich reiner Zufall und nicht

44:21.940 --> 44:22.520
beabsichtigt.

44:24.760 --> 44:27.820
Und zwar Beispiele für die damaligen Programmiersprachen, das haben

44:27.820 --> 44:29.900
Sie vielleicht in irgendwelchen Museen mal gesehen, in der Abteilung

44:29.900 --> 44:32.780
Steinzeit, FORTRAN, BASIC, COBOL, alles Programmiersprachen, die es

44:32.780 --> 44:33.480
damals schon gab.

44:34.140 --> 44:38.100
Jetzt lachen Sie nicht, die beiden habe ich auch mal gelernt, früher

44:38.100 --> 44:39.840
noch und FORTRAN habe ich auch mal selber mich ein bisschen was

44:39.840 --> 44:40.280
angelesen.

44:40.440 --> 44:43.200
Also das ist noch nicht so weit her, oder Sie finden mich jetzt

44:43.200 --> 44:43.620
steinalt.

44:45.620 --> 44:48.620
Genau, ein besonderes Merkmal von der Interkalsprache war, dass man

44:48.620 --> 44:52.260
einige Features einfach gar nicht dokumentiert hatte, was die

44:52.260 --> 44:54.340
Erlernbarkeit natürlich auch leichter machte, weil man muss weniger

44:54.340 --> 44:55.100
lernen an der Stelle.

44:55.800 --> 44:58.280
So, damit Sie jetzt sehen, worüber wir sprechen, wie bei jeder

44:58.280 --> 45:00.720
Vorstellung einer Programmiersprache, erstmal ein Hello-World

45:00.720 --> 45:01.140
-Programm.

45:01.220 --> 45:03.780
Dann hat man schon mal die einfachsten Sachen gesehen und das ist ein

45:03.780 --> 45:04.820
Interkal, sieht das so aus.

45:07.340 --> 45:16.640
So, Sie erkennen, dass man hier Dinge in einer Sequenz ausführt mit DU

45:16.640 --> 45:21.860
und dann gewisse Zeichen ausgibt an bestimmten Stellen im Speicher.

45:22.960 --> 45:24.600
Und damit ein REF wird, ja.

45:25.400 --> 45:27.500
Das hier sind alles Arrays mit dem Komma 1.

45:28.260 --> 45:32.280
Was man auch sieht ist, dass man hin und wieder auch in einem Interkal

45:32.280 --> 45:34.760
-Programm das Wort PLEASE schreiben sollte.

45:34.820 --> 45:36.300
Ja, PLEASE DU.

45:37.740 --> 45:41.660
Wenn Sie das nicht machen, gibt es einen Compiler-Fehler, der sagt,

45:42.360 --> 45:45.960
RUDE PROGRAMM.

45:46.320 --> 45:50.100
Wenn Sie zu viele PLEASE einstreuen, weil Sie vielleicht denken, Sie

45:50.100 --> 45:52.620
sind besonders clever, weil Sie jedes Mal ein PLEASE davor schreiben,

45:52.700 --> 45:53.740
kommt auch ein Compiler-Fehler.

45:54.480 --> 45:56.200
PROGRAM OVERLY POLITE ERROR.

45:58.180 --> 46:00.360
Wer von Ihnen kennt EMAX als Editor?

46:02.200 --> 46:05.440
Es gibt einen EMAX-Mode, der genau die richtige Zahl automatisch von

46:05.440 --> 46:07.060
PLEASE einstreut, statistisch.

46:07.500 --> 46:10.460
Also für EMAX-User alles einfach, für die anderen, die ein bisschen

46:10.460 --> 46:10.960
ausprobieren.

46:11.820 --> 46:14.620
Wichtig auch, die Art, wie das Programm beendet wird.

46:14.820 --> 46:15.620
PLEASE GIVE UP.

46:19.810 --> 46:21.030
Das hatte ich schon gesagt.

46:22.070 --> 46:24.850
PLEASE ist im Wesentlichen nur aus ästhetischen Gründen da, damit es

46:24.850 --> 46:26.210
nicht ganz so schlimm aussieht, das Programm.

46:30.510 --> 46:33.950
Und PLEASE wird mit DO gerne verwendet oder auch nicht.

46:35.650 --> 46:39.330
NEGIEREN erfolgt mit der Hilfe von NOT oder auch so ein bisschen

46:39.330 --> 46:40.150
genuschelt ausprobiert.

46:41.730 --> 46:43.010
Direkt nach dem IDENTIFIER.

46:43.830 --> 46:46.830
Und wie gesagt, zu viele oder zu wenige PLEASE sind auch ein Problem.

46:48.930 --> 46:49.370
DATENTYPEN.

46:49.450 --> 46:52.250
Wir haben uns in Java sehr lange rumgeschlagen mit BOOLEAN CHARACTER,

46:52.390 --> 46:53.970
BYTE, SHORT, INT, LONG, FLOAT und DOUBLE.

46:54.050 --> 46:54.790
Sie erinnern sich hoffentlich.

46:55.830 --> 46:59.570
Das ist in Intercal Significant vereinfacht, indem man sagt, ich habe

46:59.570 --> 47:02.370
einen 16-Bit-Integer, der wird mit einem Punkt eingeleitet.

47:03.170 --> 47:06.370
Oder ich habe einen 32-Bit-Integer, das ist logischerweise ja wohl ein

47:06.370 --> 47:06.930
Doppelpunkt.

47:09.010 --> 47:11.310
Mehr braucht man nicht, aber Sie müssen darauf achten, dass Sie

47:11.310 --> 47:14.090
natürlich Punkt 1,2,3 nicht mit Doppelpunkt 1,2,3 verwechseln.

47:16.590 --> 47:18.810
Nächstes Thema auch deutlich leichter als in Java.

47:20.250 --> 47:21.090
Eine Konstante.

47:21.810 --> 47:23.250
Schreiben Sie hin mit einem Hashtzeichen.

47:24.790 --> 47:26.690
In Java müssen Sie viel mehr tippen.

47:29.010 --> 47:31.570
Auch hier wieder Intercal deutlich einfacher.

47:32.030 --> 47:35.730
Auch bei Arrays ein deutlich einfacheres Konzept bei Intercal.

47:36.350 --> 47:40.510
Sie haben ein Hochkomma für einen 16-Bit-Value und ein Semikolon für

47:40.510 --> 47:41.670
einen 32-Bit-Value.

47:42.410 --> 47:46.370
Dann sagen Sie, jetzt kommt die Zahl, mit der ich darauf zugreifen

47:46.370 --> 47:47.730
möchte, also den Index.

47:47.730 --> 47:51.170
Der liegt immer zwischen 1 und eben hier 2 auf 16.

47:52.230 --> 47:55.950
Gefolgt von einem Sub, dann kann ein Leerzeichen kommen oder auch

47:55.950 --> 47:56.250
nicht.

47:58.350 --> 48:01.750
Dann kann es ein Subscript sein, was aber auch ein Ausdruck sein kann.

48:03.690 --> 48:06.550
Achtung, ab der Stelle ist es auch nicht mehr eindeutig passbar für

48:06.550 --> 48:07.050
den Compiler.

48:08.850 --> 48:11.350
Wie man damit umgeht, wird jetzt hier nicht weiter diskutiert, weil es

48:11.350 --> 48:12.350
ja eine Anfängervorlesung ist.

48:12.350 --> 48:19.310
Und man kann im Prinzip, um Ausdrücke zu vereinfachen, wenn man

48:19.310 --> 48:22.190
nämlich immer dieses Apostrophepunkt hat, das kann man auch mit

48:22.190 --> 48:23.150
Ausrufezeichen schreiben.

48:23.230 --> 48:25.190
Und deswegen sind nämlich die folgenden Ausdrücke vollkommen

48:25.190 --> 48:25.730
äquivalent.

48:26.490 --> 48:32.230
Apostrophepunkt 1 Tilde Punkt 2 Hochkomma oder eben Ausrufezeichen 1

48:32.230 --> 48:34.290
Tilde 2 Punkt 2 Hochkomma.

48:34.470 --> 48:35.250
Vollkommen dasselbe.

48:36.270 --> 48:38.810
Und den Vergleich mit Java spare ich mir jetzt, aber Sie wissen ja,

48:38.850 --> 48:40.770
wie kompliziert das in Java war mit diesen eckigen Klammern.

48:41.670 --> 48:43.310
Und jetzt sind wir schon bei einem der Highlights.

48:43.470 --> 48:44.510
GoTo gibt es natürlich.

48:45.090 --> 48:46.830
Das darf natürlich in keiner Programmiersprache fehlen.

48:48.510 --> 48:51.450
Wie ich Ihnen ja heute am Anfang erklärt habe, das definiert den

48:51.450 --> 48:52.930
Sprung zu einer bestimmten Codezeile.

48:55.190 --> 48:57.670
GoTo und wie Sie ja alle wissen, GoTo macht dem Programmierer, der

48:57.670 --> 49:01.130
Programmierer wirklich viel mehr Spaß als dem Leser, der Leserin.

49:01.870 --> 49:03.870
Weil der Programmierer in dem Augenblick hoffentlich noch ungefähr

49:03.870 --> 49:06.410
weiß, was er tut, aber derjenige, der es nachher liest oder diejenige

49:06.410 --> 49:07.490
bestimmt nicht, mehr so leicht.

49:08.690 --> 49:10.990
Die Tatsache, dass Sie möglicherweise nachher immer der Leser vom

49:10.990 --> 49:12.530
eigenen Programm sind, wollen wir mal ausklammern.

49:13.870 --> 49:17.270
Und es macht eben die Lesbarkeit und die Wachbarkeit vom Programmcode

49:17.270 --> 49:18.890
deutlich spannender.

49:21.310 --> 49:23.150
Sie erinnern sich an das Beispiel, das wir eben hatten.

49:23.270 --> 49:24.590
Das habe ich einfach rüberkopiert.

49:26.070 --> 49:27.810
Hier sieht man auch mal ganz klar die Vorteile.

49:28.570 --> 49:30.090
In Intel geht es aber noch weiter.

49:30.210 --> 49:34.230
Dieses GoTo-Konzept ist nicht das einzige, sondern Sie haben natürlich

49:34.230 --> 49:35.350
im Prinzip Next.

49:35.750 --> 49:39.130
Next ist, wenn man so will, ein Subroutinensprung, wo man sagt, ich

49:39.130 --> 49:41.010
springe an eine Adresse, kann aber auch von da aus wieder

49:41.010 --> 49:41.710
zurückspringen.

49:42.350 --> 49:46.570
Und damit kann man aber natürlich auch GoTos simulieren.

49:48.230 --> 49:51.770
Sie haben einen Stack von Rücksprungadressen, also wie oft Sie das

49:51.770 --> 49:55.830
hintereinander verschachteln können, diese Next-Aufrufe, von 79.

49:57.530 --> 50:00.430
Wenn Sie mehr als 79 Verschachtelungen haben, zum Beispiel an einer

50:00.430 --> 50:03.270
Rekursion oder sowas, dann gibt es auch tatsächlich netterweise eine

50:03.270 --> 50:03.810
Fehlermeldung.

50:03.970 --> 50:06.030
The program has disappeared in the Black Lagoon.

50:06.850 --> 50:09.290
Also Sie sollten schon freiwillig darauf achten, dass Sie diese Zahl

50:09.290 --> 50:10.810
79 nicht überspringen.

50:10.910 --> 50:13.690
Und Sie werden sich wundern, warum jetzt 79 und nicht irgendeine

50:13.690 --> 50:14.490
Potenz von 2.

50:15.570 --> 50:16.990
Tja, eine Besonderheit.

50:17.370 --> 50:18.870
Aber das Next ist harmlos.

50:19.850 --> 50:21.990
Unterprogrammsprung, das erschüttert Sie nicht weiter.

50:22.370 --> 50:25.690
Das Nächste ist schon deutlich mehr advanced und kenne ich eigentlich

50:25.690 --> 50:28.250
so in der Programmiersprache nicht als Befehl, nämlich Forget.

50:30.070 --> 50:32.690
Forget sorgt dafür, dass die Rücksprungadresse einfach mal

50:32.690 --> 50:33.370
weggeschmissen wird.

50:34.790 --> 50:38.810
Das heißt, Sie haben die elegante Möglichkeit, in eine Unterroutine

50:38.810 --> 50:41.910
reinzuspringen mit Next oder an einer anderen Stelle, als wo Sie es

50:41.910 --> 50:43.310
aufgerufen haben, wieder rauszukommen.

50:43.770 --> 50:45.010
Ist das nicht großartig, ja?

50:45.950 --> 50:48.350
So, das ist also Forget.

50:49.450 --> 50:52.450
Und im Prinzip können Sie das hier hinschreiben dann einfach so, wenn

50:52.450 --> 50:54.330
Sie mit Next hingesprungen sind, in Do Forget und jetzt haben Sie das

50:54.330 --> 50:56.230
Go -To natürlich simuliert, weil Sie können gar nicht mehr dahin

50:56.230 --> 50:59.170
zurückspringen, wo Sie hergekommen sind, aber auf eine andere Stack

50:59.170 --> 51:00.010
-Adresse, wenn Sie wollen.

51:01.790 --> 51:04.750
Diejenigen von Ihnen, die aus was für Gründen auch immer

51:04.750 --> 51:09.090
Sicherheitslücken vom Programm ausnutzen wollen, machen das natürlich

51:09.090 --> 51:11.590
auch, dass Sie mal so schnell eine Rücksprungadresse überschreiben auf

51:11.590 --> 51:12.690
dem Stack, wenn Sie das können.

51:12.830 --> 51:13.890
Und in C ist das ja gar nicht so schwer.

51:14.530 --> 51:15.550
In Java ist es schon ein bisschen schwerer.

51:16.730 --> 51:19.010
Aber wie gesagt, hier haben Sie das schon gleich implementiert in der

51:19.010 --> 51:20.450
Programmiersprache, was für ein Komfort.

51:21.850 --> 51:25.550
Sie können auch durchaus mehr Forgets machen, als Sie vorher Next

51:25.550 --> 51:26.230
gemacht haben.

51:26.610 --> 51:28.490
Da gibt es auch keine Fehlermeldung, aber da wird der Stack komplett

51:28.490 --> 51:29.850
leer gemacht und das war's.

51:31.290 --> 51:34.950
So, jetzt kommt aber zum Schluss das Highlight.

51:35.170 --> 51:37.990
Sie sollten nicht gehen, das, was Sie jetzt hier hören, werden Sie nie

51:37.990 --> 51:38.810
mehr wieder hören von mir.

51:39.110 --> 51:39.690
Come From.

51:40.990 --> 51:42.990
Come From ist das Gegenteil von Go-To.

51:43.190 --> 51:47.610
Sie erinnern sich, Go-To heißt, ich laufe irgendwo hin, komme auf Go

51:47.610 --> 51:49.830
-To, springe zu der Adresse, mach da weiter.

51:50.850 --> 51:52.150
Come From ist viel cooler.

51:53.110 --> 51:55.710
Sie schreiben einen Programmcode, das sieht alles plausibel aus.

51:56.310 --> 51:58.210
Und unten schreiben Sie in Come From 20.

51:58.870 --> 52:01.410
Und wenn Sie an der Stelle 20 sind, ohne dass an 20 überhaupt was

52:01.410 --> 52:03.050
Interessantes steht, springen Sie da weg.

52:04.710 --> 52:06.730
Und Sie springen dahin, wo halt Come From steht.

52:10.870 --> 52:13.830
Das ist meiner Meinung nach ein besonderes Feature, was ich wirklich

52:13.830 --> 52:15.450
nur von der Sprache Intercal kenne.

52:16.690 --> 52:19.890
Und Java bietet diese nützliche Funktion halt eben auch nicht an.

52:21.070 --> 52:29.350
So, dann, wie ich eingangs schon erwähnt habe, am Ende wird das

52:29.350 --> 52:30.890
Programm mit Give Up beendet.

52:32.470 --> 52:35.130
Und auch hier wieder natürlich die Literaturhinweise.

52:36.090 --> 52:40.750
Es gibt tatsächlich ein PDF dazu und es gibt auch einen Compiler zu

52:40.750 --> 52:41.890
Intercal, ob Sie es glauben oder nicht.

52:42.450 --> 52:44.290
Das können Sie hier im Prinzip runterladen.

52:44.290 --> 52:47.670
Und da haben Sie vielleicht über Weihnachten noch lustige Sachen, wenn

52:47.670 --> 52:49.970
Sie noch die anderen Befehle, die ich jetzt nicht hatte, und auch

52:49.970 --> 52:51.450
Forget hat nicht gemacht, weil er einfach so cool war.

52:51.850 --> 52:54.590
Aber wie gesagt, die anderen Befehle, es gibt noch weitere Befehle,

52:54.650 --> 52:55.110
haben Sie da nicht.

52:55.990 --> 53:00.470
Und insofern hier also nochmal die Zusammenfassung dazu.

53:02.050 --> 53:04.230
Die Programmiersprache würde wirklich sehr einfach gehalten.

53:04.470 --> 53:07.110
Dummerweise war das eher für den Deklarierer der Programmiersprache

53:07.110 --> 53:08.410
ein Vorteil als für den Programmierer.

53:09.370 --> 53:11.930
Sie entspricht natürlich vollkommen der natürlichen Intuition des

53:11.930 --> 53:12.550
Programmierers.

53:12.550 --> 53:15.450
Ein Konzept wie Come From ist relativ offensichtlich, was es macht.

53:17.190 --> 53:19.350
Und diese ganzen neumodischen Schnickschnacken, mit denen Sie jetzt

53:19.350 --> 53:21.550
die ersten Monate hier verbringen mussten, und mit denen ich Sie

53:21.550 --> 53:24.950
gequält habe, wie Typsysteme, Objektorientierung, wo man sich dann

53:24.950 --> 53:28.530
auch noch so Krankheiten einhandelt, wie Vererbung, Polymorphien in

53:28.530 --> 53:31.070
den verschiedensten Ausprägungen, braucht man alles nicht.

53:32.150 --> 53:35.170
Also Sie sehen, Intercal ist perfekt geeignet für Anfänger.

53:35.670 --> 53:38.310
Tatsächlich steht auch in dem Manual drin, dass man, also damit

53:38.310 --> 53:40.730
dachte, dass man, wenn man das den Anfängern gibt, sie leicht zum

53:40.730 --> 53:41.390
Programmieren hinführt.

53:42.550 --> 53:45.470
Die Erfahrung hätte aber gezeigt, offenbar im Princeton, dass es eher

53:45.470 --> 53:48.170
dafür geeignet wäre, den Anfängern eine andere Berufslinie irgendwie

53:48.170 --> 53:48.810
nahezulegen.

53:50.870 --> 53:54.210
Deswegen ist das auch eben mein Weihnachtsgeschenk für Sie und nicht

53:54.210 --> 53:55.370
prüfungsrelevant natürlich.

53:56.170 --> 53:59.390
Ich wünsche Ihnen ein frohes Fest, gesegnete Weihnachtsfeiertage, viel

53:59.390 --> 54:03.110
Erholung, einen guten Rutsch ins neue Jahr und kommen Sie dann

54:03.110 --> 54:05.190
nächstes Jahr wieder gut an.

54:05.310 --> 54:07.830
Achtung für die Nicht-Baden-Württemberger, ein Klammern, ich bin ja

54:07.830 --> 54:11.850
auch einer, hier in Baden-Württemberg fängt alles nach Heilige Drei

54:11.850 --> 54:12.890
Könige erst wieder an.

54:13.450 --> 54:15.750
Also machen Sie gar nicht erst den Versuch, dieses Bundesland in

54:15.750 --> 54:18.450
irgendeiner Form anzusprechen in der ersten Januarwoche, hier ist

54:18.450 --> 54:19.410
alles noch im Sleep-Modus.

54:20.150 --> 54:22.310
Und stehen Sie nicht, wie ich mal blöd, irgendwie als Rheinland

54:22.310 --> 54:24.370
-Pfälzer vor der Tür und wundern sich, dass hier nichts los ist.

54:25.730 --> 54:28.070
Alles Gute und dann, wie gesagt, bis zur zweiten Januarwoche.

