So, 3, 2, 1, 14.15 Uhr in Deutschland. 14.15 Uhr,
nicht nur in Deutschland, sondern im wunderschönen,
sonnigen Hamburg und wie ich sehe, haben viele,
also sie nicht,
aber viele ihrer Kommilitoninnen mit großem I nutzen die Zeit heute
offensichtlich anders als hier zu sitzen und sich Fred Winkler und
mir zuzuhören
Nun, ich hoffe,
diejenigen von Ihnen, die den Weg hierhin gefunden haben,
sind nicht enttäuscht über das kleine Feuerwerk,
das wir in den nächsten anderthalb Stunden hier abbrennen werden.
Dass ich heute um circa 15.30 Uhr diese Vorlesung verlassen werde,
hat nichts mit dem Wetter zu tun.
Ich habe um 16 Uhr einen auswärtigen Termin,
deswegen kann ich Fred nicht bis zum Ende zuhören.
Aber ich gucke mir das dann auf Lecture to go an.
So, heute werde ich mit Ihnen
über zwei Themen sprechen
Dieses, das erste Thema sehen Sie hier. Wir wollen uns dem Thema widmen,
wie kann man in einer objektorientierten Programmiersprache am Beispiel Java,
wie kann man systematisch sogenannte Fehlerbehandlung implementieren,
wie kann man so mit Fehlern umgehen,
dass also ein gesittetes Ingenieur wissenschaftlich sauberes Verhalten implementiert wird in ihren Programmen.
Das zweite Thema wird so ein letzten Drittel meines Vorlesungsteils, wird es Raum einnehmen.
Wir werden uns nochmal mit dem Thema Sichtbarkeit beschäftigen.
Da werden wir noch ein zusätzliches Sprachmittel kennenlernen, das konzeptionell einordnen.
Das soll Ihnen helfen. Sie sind ja jetzt auf dem Weg erfahrene Programmierer zu werden,
auch größere, größere Programme strukturieren zu können,
sodass sie die Komplexität, die inhärente Komplexität großer Programmsysteme,
die die mit sich bringen, noch besser beherrschen können.
So, jetzt aber erstmal zum Thema Fehlerbehandlung mit Exceptions.
Da sind sie in einer halben Stunde, sind sie viel
schlauer als jetzt. Wenn wir uns mit Fehlern beschäftigen,
ist so ein Getreu dem Motto, Teile und Herrsche,
die Frage, was ist ein Fehler, die beantworten wir,
indem wir zunächst mal zwei Fragen daraus machen.
Das Konzept des Fehlers Unterteilen wir zunächst mal in zwei
Arten von Fehlern, die wir zukünftig unterscheiden werden.
Die erste Kategorie sind die sogenannten Entwicklungsfehler. Entwicklungsfehler sind alle Fehler,
die sie machen. Man könnte auch sagen, Entwickler,
Entwicklerinnen mit großem I-Fehler. Also Fehler, die passieren,
während sie programmieren. Die zweite Art von Fehler,
die wir unterscheiden müssen, oder sagen wir mal,
die Unterscheidung, die sich anbietet, ist,
sind Fehler, die zur Laufzeit eines Stück Softwares auftreten,
die in der Umgebung des Programms, dass sie fehlerhaft entwickelt haben, auftreten.
Das sind die sogenannten Umgebungsfehler. Wenn ich jetzt also diese beiden Begriffe,
Entwicklungsfehler und Umgebungsfehler, was ich hier getan habe,
beziehungsweise was die Autoren dieser Folie getan haben, ist,
sie haben eine sogenannte Extension, umgekehrt, eine intentionale Definition dieser Arten von Fehler gegeben.
Jetzt schauen wir uns mal die Extension an,
also Beispiele für diese Arten von Fehlern und zu ihrer Orientierung
gibt es da schon Hinweise,
um welche Art von Fehler es sich jeweils handelt
Was so eine Art von Fehler ist das,
wenn eine Implementation nicht die Anforderungen ihrer Spezifikation erfordert.
Offensichtlich ist es ein Entwicklungsfehler, weil das ist ein Fehler,
der passiert ist, während sie programmiert haben.
Das zweite Beispiel, das ist zur Laufzeit, offensichtlich zur Laufzeit
passiert das in einem Programm. Sie schreiben ein Programm,
das möchte man auf eine Datei zugreifen und dann hat irgendeiner
irgendein anderer Mensch hat, also im Betriebssystem dafür gesorgt,
dass sie keine Schreibzugriffe auf dieses Programm haben,
dann ist das wohl ein Umgebungsfehler.
Und wir machen jetzt diese Unterscheidung Die wird später noch eine Rolle spielen.
Die anderen Beispiele schauen sie, auf die schauen sie,
während ich hier spreche. Wir machen diese Unterscheidung,
weil wir auf unterschiedliche Arten von Fehlern im Programm auch unterschiedlich reagieren wollen. Das Entwicklungsfehler werden typischerweise,
wir werden uns das anschauen, werden anders behandelt als Umgebungsfehler,
sodass das jetzt nicht so eine reine definitorische Unterscheidung ist,
sondern das hat nachher auch eine Unterscheidung gemacht auch nachher bei
der Art der Behandlung dieser unterschiedlichen Arten von Fehlern,
auch einen Unterschied aus,
was man tun kann,
wenn diese Fehler auftreten
So, also jetzt erstmal die Unterscheidung zwischen Entwicklungs- und Umgebungsfehler,
die behalten Sie mal im Hinterkopf.
Nicht erst, seit es objektorientierte Programmiersprachen gibt, gibt es Fehler.
Man könnte sagen, also die Geschichte des Programmierens ist die Geschichte des Machens von Fehlern.
Und deswegen gibt es auch schon sehr, sehr lange Ansätze.
Wie kann man damit um, wie kann man damit umgehen,
dass erstens menschenfehlerhaft programmieren, Entwicklungsfehler.
Und das ist zu der Zeit, in der das Programm ausgeführt wird,
zu Situationen kommt, die die Programmierer nicht vorhergesehen haben.
Also hatten sie sich die Menschen, Softwareentwickler,
haben sich da unterschiedliche Arten von Fehlerbehandlungen ausgedacht.
So das Einfachste, was man machen kann, das ist,
man macht nichts. Es kommt zu einem Fehler und das Programm
wird aus der fehlerhaften Methode aus der fehlerhaften Operation heraus abgebrochen.
Unbekannter Fehler, bumm aus. Das ist jetzt aus Sicht
des Entwicklers, ist das eine nachvollziehbare Reaktion
Ist eine Situation eingetreten, mit der ich nicht umgehen kann.
Also höre ich auf. Oder das Programm hört. Das
ist das von mir geschriebene Programm. Hört dann auf.
Wir gucken uns gleich mal an. Das haben sie bei
der Verwendung ihres Computers bestimmt schon häufiger gehabt. Und naja,
gut, dann ist das halt so, je nachdem,
was für ein Typ sie sind, regen sie sich jetzt auf,
schmeißen den Computer weg oder kaufen sich ein neues Stück Software.
Das ist alles noch im Rahmen. Also da geht es
nicht um sicherheitskritische Anwendung. Das kann man also machen.
Optimal ist das sicher nicht. Zweite Methode,
das ist schon etwas cleverer
Eine Methode wird aufgerufen, die stellt meinetwegen fest,
dass ein Parameter außerhalb eines Wertebereichs liegt, den diese Methode verarbeiten kann.
Was macht, sagen wir mal, diese Methode soll eigentlich
ein Integer-Wert zurückliefern. Und was die dann tut, ist,
sie retourniert minus eins. Weil der Programmierer sich gedacht hat,
also wenn ich jetzt minus eins zurückgebe,
dann muss das doch von demjenigen, der mich aufgerufen hat,
muss das als fehlerhaft interpretiert werden.
Sagen wir mal, diese Operation,
die Funktion heißt Wurzel
Sie rufen Wurzel mit dem Parameter minus vier auf.
Dann geben sie als Rückgabewert minus eins und sagen,
hey, das geht so nicht, oder?
Okay. Das kann man machen. Also es ist also eine andere,
eine andere Art von Verhalten, als das Programm abzubrechen.
Das könnten sie ja auch tun. Die dritte Methode,
das ist etwas, das können sie in den objektorientierten Programmieren,
in der objektorientierten Programmiersprache,
die wir ihnen jetzt hier nahe bringen,
ist es schwer zu realisieren,
eine global lesbare Variable
Auf einen Wert zu setzen, sodass so für den Klienten
dieser Methode einer Methode deutlich ist, es ist ein Fehler passiert.
So, es könnte ja eine globale Variable geben namens Fehler.
Und die könnte ein Bulien sein und den setzen sie dann
in der aufgerufenen Methode auf True.
Dann sagen sie es so. Und jetzt mache ich weiter.
Okay, das ist eine andere Art mit Fehlern umzugehen.
Und dann gibt es etwas, das haben sie so,
glaube ich, noch gar nicht kennengelernt, das werden wir noch kennenlernen, sogenannte Call-Back-Operation.
Das sind Operationen, die spezifisch dafür geschrieben werden, dass Fehlersituationen aufgetreten sind.
Und dann rufe ich genau diese Methode auf,
um dem Aufrufer zurückzurufen und zu sagen, es ist ein Fehler passiert.
Das ist eigentlich so, das geht deutlich in die Richtung dessen,
womit wir uns jetzt die nächsten Minuten hier beschäftigen werden.
Das sind so eine traditionelle Methode. Und jetzt komme ich mal kurz dazu,
diese Arten der Fehlerbehandlung zu diskutieren und zu sagen,
warum das noch nicht der Weisheit letzter Schluss ist, so Programmabbruch.
Also insbesondere bei Sicherheitskritischen Systemen ist das ein nicht tragbares Verhalten.
Also ich möchte, ich kenne mich mit der Steuerung von Flugzeugen und Flugzeugsoftware
wirklich überhaupt gar nicht aus. Aber bei dem Gedanken,
dass so ein Flugzeug einfach mal die Software runterfährt,
weil es zu einer Situation gekommen ist, lässt mich dann doch überlegen,
ob ich den nächsten Urlaub nicht lieber im Schwarzwald mache und da mit dem Fahrrad hinfahre.
Also das ist nicht akzeptabel. Das will man nicht.
Ich gehe mal davon aus, dass auch keine Zulassungsbehörde
ein solches Stück Software zertifizieren würde.
So, der zweite, der zweite Ansatz der Return-Wert
Nicht immer, steht da so schön, lässt sich ein
geeigneter Wert finden, der als Fehlercode interpretiert werden kann.
Wenn Sie, um bei dem Wurzelbeispiel zu bleiben,
Sie kriegen als Wert halt minus eins zurück und wenn Sie sich nicht mit Wurzelberechnungen auskennen,
denken Sie halt, na gut, ist halt so, oder?
Dann kriege ich halt minus eins als Rückgabewert. Wenn das jetzt für Sie ist,
das sind hanebüchendes Beispiel, aber wenn man sich nicht so knietief mit der jeweils zu implementierenden Problematik auskennt,
kann einem das ja durchaus passieren, dass man bei komplexeren Berechnungen Werte zurückgibt,
die man als Programmierer nicht wirklich interpretieren kann,
sondern sie so nimmt, wie sie sind.
Also das ist Das Zweite, was dazukommt, ist,
selbst wenn ich das jetzt interpretieren kann,
als einen nicht akzeptablen Wert, muss ich denn jedes Mal,
muss ich das jedes Mal überprüfen, also was da jetzt zurückkommt.
Also wir haben ja jetzt mittlerweile auch schon das Vertragsmodell kennengelernt und das Vertragsmodell gibt ihnen ja auch schon so eine Anleitung dazu,
wie man dann mit solchen Situationen umzugehen hat,
so dass du so in diesem Fall,
also die gerufene Operation, wenn sie meint,
dass die Vorbedingungen nicht eingehalten worden sind,
dass die dann darauf reagieren können und wie sie das in Java tun kann,
das werden wir eben heute kennenlernen.
So das dritte ist die globale Fehlervariable,
das ist eigentlich ähnlich zu beurteilen wie die zweite Operation
Also ich vergesse das ja dann auch einfach mal, nachzuschauen,
ist denn diese globale Fehlervariable jetzt wirklich gesetzt worden vorher,
war sie vorher umgesetzt, ist die Nachtaufruf einer Operation, ist sie dann gesetzt.
Das ist, das Verfahren ist einfach nicht sicher genug,
ist nicht sicher genug, um es systematisch anzuwenden.
Ich habe schon zu Callbacks, habe ich schon gesagt,
es geht in die richtige Richtung, allerdings Auch wenn das eine etwas seltsame,
die Blähung als Metapher für Softwareentwicklung etwas schräg erscheint,
aber naja gut, also was damit gemeint ist,
ist, der Code wird einfach unübersichtlich.
Und ich möchte eigentlich vermeiden, dass die Fehlerfälle so beim
Bloßen draufschauen auf den Code, also die Hauptaufmerksamkeit erzeugen.
Und ich möchte, dass der Standardfall der Happy Path,
der sollte eigentlich das Verständnis der Software prägen. So,
nachdem ich jetzt diese so als dramaturgisch, was ich jetzt getan habe,
ist, ich habe jetzt den schwarzen Ritter aufgebaut,
also alles ganz furchtbar, traditionelle Ansätze.
Jetzt betritt der weiße Ritter die Bühne. Und dieser weiße Ritter heißt
die Ausnahme. Das hört sich nicht viel besser an als Fehler,
aber wir werden uns jetzt damit beschäftigen, dass Ausnahmebehandlung,
also der Umgang, der systematische Umgang mit Fehler, mit Fehlern,
der hat dann so offensichtlich dann doch eine so große Bedeutung gehabt,
dass er als eigenständiges Sprachkonzept heutzutage in objektorientierten Programmiersprachen Eingang gefunden hat.
Wir sehen jetzt so einen Blick in die Geschichte
Gab es also Programmiersporte, gibt es immer noch Programmiersprachen,
wie Clou, Cluster, das ist kurz für Cluster,
die früher etwas weiter verbreitete Programmiersprache,
Ader seien mittlerweile ziemlich auf dem Rückzug,
programmiert kaum noch jemand drin.
Eifel, die Programmiersprache haben wir schon mal erwähnt.
Das war nämlich die Programmiersprache,
die als erstes das Vertragsmodell implementiert hat.
All diese Sprachen hat mal jemand
ein Taschentuch
Hallo? Ja, besser, danke. So,
wenn man jetzt also mal eingesehen hat, das Programmieren,
ein fehlerhafter,
mit Fehlern behafteter Vorgang ist und man mit systematisch mit Ausnahmen
umgehen möchte,
dann schreibt man sich
diese Ziele hier
Auf die, also als Programmiersprachenentwickler, diese Ziele auf die fahren.
Ich möchte systematisch mit Fehlersituationen umgehen können und systematisch bedeutet insbesondere,
dass die Fehler nicht einfach ignoriert werden können. Ich möchte den Normalfall nicht verschütten und ich,
das jetzt kommt so, das habe ich auch schon gesagt,
es kommt noch so ein drittes Ziel dazu, bin ich Umgebungsentwicklungsfehler,
ich möchte die Fehler nicht nur auf dieser Ebene unterscheiden können,
sondern ich möchte in einer Fehlersituation demjenigen,
der in der Lage ist, so mit diesem Fehler umzugehen,
so viele Informationen wie möglich darüber geben,
Wie ist es zu dieser Situation gekommen?
Alles, was hilfreich sein könnte, um diesen Fehler zu beheben?
So, was Java ihnen dafür zur Verfügung stellt,
sind sogenannte Exceptions. Das sind jeweils Exemplare einer Exception-Klasse und
ich habe in einer der vorherigen Vorlesungen auch schon gezeigt,
so mal eine Übersicht über die Vererbungshierarchie, der Exception-Klassen.
Der Punkt, also das, was für Sie jetzt so an der Stelle,
wo es also bekannt ist, Terrain eigentlich betreten werden sollte,
Exceptions sind Objekte, Objekte eines bestimmten Typs, einer bestimmten Klasse.
Das heißt, das ist nichts anderes als das,
was sie, seit sie hier sich mit Java in SE1 beschäftigen.
Es ist nichts, also konzeptionell Neues. Sie werden bloß in der Art und Weise,
wie sie verwendet werden, helfen sie ihnen,
Aussagen zur Laufzeit eines Programms zu machen,
die sie bisher nicht machen konnten,
nämlich mit den Ausnahmen umzugehen,
mit denen so den Unwägbarkeiten des Alltags,
die während des Programmablaufs auftreten
So, sie können, also vorhandene Acception-Klassen verwenden,
Objekte von diesen Acception-Klassen erzeugen und sie können sich auch eigene Acception-Klassen schreiben,
wenn sie also der Ansicht sind,
ich schreibe hier ein Programm und dem, in dem Können,
also Fehlersituationen auftreten, die sind so speziell,
dass ich eigene Acceptions werfen können möchte.
So, da können sie dann zusätzliche Informationen,
also das, was ihnen sinnvoll erscheint,
um den Fehler beheben zu können,
zusätzliche Informationen unterbringen
Jetzt hatte ich letztes, letzte Vorlesung schon behauptet, es gibt keine zusätzlichen Schlüsselwörter mehr.
Fred hat mich unmittelbar berichtigt und hier sehen sie jetzt so den,
ich behaupte das jetzt nicht nochmal,
aber so soll man den vorläufig finalen Satz,
an Schlüsselwörtern, den sie in Java kennenlernen,
um in diesem Fall die Ausnahmebehandlung zu beherrschen.
So, wir gehen die mal einmal kurz durch,
um sie dann mal in der Anwendung zu zeigen.
Wenn Sie eine Ausnahmebehandlung auslösen wollen, dann können Sie das mit dem Schlüsselwort Through tun.
Through, ja, auslösend werfen. An jeder beliebigen Stelle Ihres Programms können Sie sagen,
also ich werfe hiermit eine,
ich löse hiermit eine Acception aus und dann wird,
wir gucken uns das gleich noch an,
dann wird ein Acception Handling,
wird dann angeworfen und das führt im Zweifelsfall am Ende,
wenn man nicht anders darauf reagiert,
zu einer Beendigung des Programmes
Das ist jetzt nichts anderes als das, was ich vorhin als Methode 1 charakterisiert habe.
Das Programm hört einfach auf. Der Unterschied sollte darin bestehen,
dass die ihr Programm gesittet abgebrochen wird. Und gesittet bedeutet nicht,
bedeutet nicht, es ist also so eine Fehlermeldung oder ein Stackdump,
was auch immer, dem Benutzer erscheint,
sondern dass dieses Programm das tut, was es noch tun muss,
um also mindestens nochmal wieder vernünftig gestartet werden zu können.
Wenn man eine solche Exception auslösen kann, dann muss sie auch irgendwo deklariert werden.
Und das ist etwas, das ist ein Stück Code,
das werden wir uns noch anschauen. Wenn sie auf Code treffen,
der eine Ausnahme auslösen kann, dann dürfen sie den nicht einfach aufrufen.
Was sie dann tun müssen, ist, sie müssen vorsichtig versuchen,
ihn aufzurufen. Und dieses vorsichtig Versuchen, also drückt man nicht dadurch aus,
dass sie einen kleineren Font benutzen, dem Editor,
was von der Sorte oder in Zartrosa den Coach schreiben,
wenn dann dieses vorsichtige Anklopfen, drücken sie dadurch aus,
dass sie einen sogenannten Tri-Blog deklarieren.
Das bedeutet nichts anderes als der Code, den sie schreiben,
muss eingebettet werden in eine Try-Anweisung. Dann weiß also der Übersetzer schon,
aha, der Klient eines Stücks Codes rechnet damit aus guten Gründen,
weil an der Stelle, die ihr aufruft,
also kann eine Exception ausgelöst werden, rechnet damit,
dass es tatsächlich dazu kommt, Das ist so einer,
dass die Exception ausgelöst wird.
Und wenn diese Exception ausgelöst wird, dann ist derjenige,
der vorsichtig versucht, diesen Code auszuführen.
Auch in der Lage, diese Ausnahme zu behandeln.
Wenn also hier eine Ausnahme ausgelöst wird durch Throw, dann ist derjenige,
der den Code aufruft innerhalb eines Triblockes in der Lage,
diese ausgelösene,
diese geworfene Ausnahme zu fangen
Das ist der Catchblock innerhalb. Also das ist so eine
ganz typische Struktur, die sich dann im Code ergibt.
Das sind so Try-Catch-Sequenzen. Try, ich rufe den Code auf,
der eine Ausnahmebehandlung auslösen kann. Und da drunter der Catchblock,
wenn diese Ausnahme tatsächlich ausgelöst wird, dann fange ich die und kann,
wie ich das vorhin ausgedrückt habe, gesittet darauf reagieren,
dass diese Ausnahme tatsächlich eingetreten ist.
Und dann gibt es so noch etwas,
das heißt finally, nach dem Motto, letzte Worte,
Wenn eine Ausnahme ausgelöst worden ist,
dann möchte ich in jedem Fall noch irgendwelche Verbindungen schließen,
Dateien zurücksetzen, was auch immer,
noch unbedingt getan werden muss, bevor der Catchblock beendet wird.
So, das sind jetzt so die grundsätzlichen Ideen zum Thema,
oder also die grundsätzliche Art und Weise,
wie Ausnahmen behandelt wird.
Wir schauen uns das jetzt noch so etwas detaillierter an,
bevor ich dann zu dem Code Beispiel komme
So, zunächst mal. Ich fange mal hier an. Hier wird eine,
wenn eine Ausnahme ausgelöst wird, dann ist es zu einer,
kommt es dazu, dass eine Ausnahmebedingung eingetreten ist.
Und was heißt denn das? Das heißt, die auslösende
Methode, also die in der Regel die gerufene Methode,
die wird abgebrochen. Und dann geht der Kontrollfluss,
geht an die Stelle zurück, von wo aus diese Methode,
die die Ausnahme ausgelöst hat, aufgerufen wurde.
Das ist also so eine Art von Rücksprung
Also sie haben jetzt, wenn sie sich erinnern, das,
was ich gerade gesagt habe, also wenn so ein Throw passiert,
dann muss an der Stelle, wo es aufgerufen worden ist,
der in dem Trial-Block, so ist ja der Kontrollfluss,
dann geht der Kontrollfluss direkt zurück in den Catch-Block,
der aufrufenden Stelle.
Das heißt, es ist so eine Art von Rücksprung.
Was jetzt passiert ist, das ist eigentlich ganz folgerichtig,
wenn in dem Catch-Block, wenn man da auch nicht weiter weiß,
so was man jetzt machen soll mit der Fehlersituation,
die dort eingetreten ist, dann geht die Aufrufreihenfolge zurück
Und das ist bis zu der Stelle, bist du der Main-Methode,
wo das Programm ursprünglich mal gestartet wurde.
Und das ist das für ein Verhalten, das sie jetzt
in ihren Programmen möglicherweise auch schon mal beobachtet haben.
Wenn Sie also an einer tief verwurzelten Stelle in Ihrem Programm mal
eine Array Index out of Bounds Exception, wenn die ausgelöst wurde,
und Sie konnten damit, Sie sind damit nicht umgegangen,
konnten Sie ja bis jetzt auch nicht.
Dann haben Sie mal diesen Calls Deck gesehen,
der dann so weit auf ihnen gezeigt hat,
also wie ist es dazu gekommen, dass diese Acception ausgelöst wurde.
Das ist also eine Folge von Rücksprüngen, die dann stattgefunden hat.
So, und das ist auch genau das, was hier steht. Das ist also bis,
so wenn eine Ausnahme überhaupt nicht abgefangen wird, dann,
also geht der Rücksprung letztendlich bis zur Main-Methode ihres Programms und die Main-Methode,
die kann darauf reagieren,
dass irgendwo eine Acception ausgelöst worden ist und das ist die
Reaktion der Main-Methode,
die Standardreaktion ist der Programmabbruch
So, jetzt kommen wir mal dazu,
wie man das im Java-Code, so ohne,
dass sich jetzt Fred zu weit vorgreifen möchte, wie komme ich dazu?
Oder wie sieht das aus, wenn ich das im Java-Code
tatsächlich mal verwenden möchte? So,
da gibt es jetzt zunächst mal zwei Arten von Ausnahmen,
also die, die ich unterscheiden können möchte.
Und jetzt kommen wir nämlich zurück auf das,
womit ich angefangen habe, auf Umgebungsfehler und Entwicklungsfehler.
So, für die Umgebungsfehler werden sogenannte geprüfte Exceptions ausgelöst und
für Entwicklungsfehler werden ungeprüfte Exceptions ausgelöst.
Und sie sehen hier auf der Folie auch so ein paar Beispiele dafür.
Ich finde, dass so von der Pragmatik her geprüfte Exception,
finde ich das ein bisschen dubios, geprüfte Exceptions werden für vorhersehbare Fehler eingesetzt.
Da fragt man sich vorhersehbare Fehler,
kann man die
nicht einfach vermeiden
Wenn ich das schon vorhersehen kann, was soll denn das? Naja,
das kann man, also ich habe mich das gefragt,
aber die Beispiele, die sie da sehen,
also sie sind hoffentlich so einleuchtend, man kann das vorhersehen,
aber man kann es trotzdem nicht vermeiden.
Ganz im Gegenteil, das, was man vorhersehen kann,
als etwas, was schiefgehen kann. Darauf sollte man
sich vorbereiten. Und deswegen sind das auch geprüfte Exceptions.
Also sowas wie ein Timeout bei einer Verbindung zu einem anderen Prozessraum
oder dass ein Server, auf den man wartet, dass der nicht reagiert.
Das sind die Arten von vorhersehbaren Fehler, auf die ich so,
die in der Umgebung meines Programmes auftreten können und auf die reagiere ich mit den geprüften Exceptions.
So, bei den ungeprüften Exceptions, das sind,
die sind sozusagen nicht vorhersehbar, da war einfach jemand,
also, wie soll ich sagen, zu blöd,
nicht diszipliniert genug, zu müde,
was auch immer,
aber Array Index out of Bounds Exceptions oder das Null Pointer
als Parameter übergeben worden ist
Das sind diese Art von Entwicklungsfehlern, also unvorhersehbar, macht man einfach, passieren einfach.
Und die braucht man nicht zu deklarieren, eben weil sie einfach passieren.
Das ist sozusagen dieses Nichtwissen, das kann ich ja auch schlecht,
also durch eine geprüfte Exception, kann ich das darstellen. So,
wir haben eine ganz einfache Regel für den Umgang mit geprüften Ausnahmen,
wenn eine Methode, ah, eine andere Methode B benutzt,
naja gut, die eine geprüfte Exception deklariert,
müssen in der Methode A, Vorkehrungen getroffen werden,
um mit dieser Acception umzugehen.
Das wird also, und das ist nicht nur eine Regel,
sondern das wird durch die Programmiersprache Java,
wird es auch erzwungen, dass sie das tun.
Weil wenn ich schon, also wenn die Methode B schon sagt,
ich werde eine Acception auslösen in dem Moment,
so wo ein Fehler auftritt, dann muss die Methode A darauf reagieren.
Das reagieren kann aber auf zwei verschiedene Arten passiert.
Ich kann diese Exception selbst behandeln oder ich propagiere sie weiter.
Das ist ein etwas feinerer Ausdruck für, ich gebe es an den,
der mich gerufen hat, gebe ich das weiter.
Ich tue also im Wesentlichen nichts. So sieht das dann
im Java-Code aus. Ich habe das schon mit der versucht,
mit meiner Gestik ein bisschen zu erläutern. Also der Tri-Block,
das ist der Block,
in dem die Anweisungen gerufen werden in der Methode B in dem Beispiel,
in der Regel gerade, die zu einer Exception führen können.
Falls das tatsächlich passiert, dann kann ich in dem Catch-Block,
wenn die Exception also geworfen worden ist,
kann ich diese Exception dort behandeln. Und unabhängig davon,
ob die Exception aufgetreten ist, ist in dem Finaly-Block,
stehen die Anweisungen, die auf jeden Fall ausgeführt werden.
Also nach Aufruf der Methoden hier, die eine Exception auslösen können.
So, jetzt, den Rest wird Ihnen dann Fred
mit der Hand am Arm im Java-Code zeigen.
Ich liebe diese Art von Rückkopplung. Jetzt komme ich noch
dazu in den letzten Minuten
Etwas über, so, wie man so sagen, könnte jetzt überleiten.
And now for something completely different. Namensräume und Modularisierung.
Dieses Konzept, wo wir durch so eine Überleitung,
ist eine Überleitung, liegt eigentlich ganz auf der Hand.
Wir haben über, jetzt über traditionelle Konzepte der Fehlerbehandlung gesprochen.
Und jetzt könnte man über traditionelle Konzepte der Modularisierung sprechen
Eine Kenngröße zur Verwendung von Computern. Ich sagte ihnen jetzt,
die wird ihnen möglicherweise nie wieder in ihrem Leben begegnen.
Das ist die Mean-Time Between Failure.
Kurz MTF. Ist auch nicht prüfungsrelevant, dieses Wissen.
Das ist eigentlich völlig überflüssiges Wissen. Mean-Time Between Failure gibt
an, wie lange dauert es durchschnittlich,
bis ein Computer zusammenbricht
Und das ist eine Größenordnung, die wurde früher in Sekunden gemessen,
also viel früher. Es ist so viel früher,
so zu der Zeit, als ich so geboren wurde,
also in den frühen 60ern, als ihre Eltern möglicherweise daran dachten,
dass sie mal Kinder haben wollen.
Und wenn man jetzt ein langes Stück Programm hat,
dann, und man ausrechnen kann,
dieses Stück Programmtext zu übersetzen,
dauert meinetwegen
zehn Sekunden
Die Mean-Time-Between-Failure ist aber acht Sekunden. Also wird man in vielen Fällen,
wird es einem nicht gelingen, dieses Stück Programmtext zu übersetzen.
Was macht man jetzt? Okay, man könnte versuchen,
bessere Hardware zu bauen. Also die Mean-Time-Between-Failure auf zwölf Sekunden anwechseln,
dann hat man dieses Problem gelöst. Sondern etwas grundsätzlichere Art
mit dieser Art von Problemen umzugehen ist, man schafft kleinere Übersetzungseinheiten.
Das ist also mehr so eine Aufgabe, die hier stattfindet,
als dass man jetzt neue Hardware braucht. Also wenn ich es schaffe,
das Stück Software, für das ich der übersetze,
zehn Sekunden braucht, den zwei,
meinetwegen gleich große Teile zu zerlegen und die getrennt übersetzt werden können und dann die getrennt übersetzten Einheiten,
die kriege ich dann,
also irgendwie durch einen Zauber kriege ich die zusammen zum Laufen.
Dann habe ich also fünf Sekunden und das schaffe ich mit der
gerade zur Verfügung stehenden Hardware. Das ist ein intellektuell,
ist das ein etwas größerer Anspruch,
aber das ist so die Idee der sogenannten Modularisierung stammt,
also aus diesem ganz unter anderem diesem ganz praktischen Grund.
Ein zweiter Grund, das sehen Sie jetzt schon hier,
Was ist das? Keine Ahnung. Das könnte, könnte ein,
könnte ein UML-Diagramm sein. Das könnte aber auch was anderes sein.
Es sieht auf jeden Fall relativ unübersichtlich aus. So die Frage,
die man an diese Art von Diagramm stellt, ist vielleicht,
hat es Sechsvolt oder hat es 12 Volt?
Und wenn man diese Frage beantwortet hat, ist man dann schlauer?
Jetzt mal abgesehen davon, dass ihn jemand erklären kann,
was die Grünen und die roten Pfeile bedeuten.
Sie sollten sich in einer ruhigen Minute, googeln Sie doch
mal den Artikel Real Programmers, don't use for tran.
Und jetzt, wo ich das gesagt habe, fällt mir ein,
der Artikel heißt Real Programmers, don't use Pascal.
Es ist nämlich genau umgekehrt, den echten Programmierer,
die verwenden nämlich Fortreiben. Und jetzt nehmen wir mal an,
da sei ein Fortrein-Programm, sei ein Pascal-Programm.
Von mir aus kann es auch ein Java-Programm sein,
bestehend aus 300 Klassen
Wenn Ihnen jetzt jemand die Aufgabe stellt,
machen Sie das mal, um Faktor 2,5 schneller.
Sie haben eine Woche Zeit, wenn Sie wahrscheinlich auch denken,
ich suche mir lieber einen anderen Job.
Das will man nicht. So sehen,
aber so können Strukturen von Programmen aussehen,
wenn Sie als Building-Blogs für diese Programme nur Klassen haben.
Stellen Sie sich vor, Sie schreiben jetzt mal,
stellen Sie sich das lieber nicht vor
Sie kommen in eine Situation, ein Projekt, das über ein,
zwei Jahre läuft und sie bauen jetzt ein Stück Software in Java von mir aus,
so um die 5.000, 6.000 Klassen groß ist,
was keine besonders große Zahl ist.
Das ist, das geht. Das geht schnell.
Dann möchten Sie oberhalb von Klassen möglicherweise ein Strukturierungskonzept haben.
Und diese Strukturierungskonzept sollte nicht nur in den Köpfen der Programmierer sein,
sondern die Sprache sollte, dieses Strukturierungskonzept auch noch unterstützen.
Und das ist, und die Grundidee, des Modulkonzeptes,
das dann auch in Java, in einer Art und Weise realisiert worden ist.
So jetzt zunächst mal dieses Modulkonzept, also der Begriff des
Moduls ist ihnen ja auch aus anderen Kontexten möglicherweise bekannt.
Hey, aus ihrem Studium zum Beispiel,
das Modul Softwareentwicklung 1. Das hat doch eine klare Schnittstelle.
Es besteht aus Vorlesung, Übung, Programmierdiktat, was weiß ich,
was da alles noch drin ist. So, das ist jedenfalls,
es hat eine klare, ich würde es nicht übertreiben,
aber das hat eine noch eine klare Beziehung zur Außenwelt.
Sie haben verschiedene Module, die zusammengesetzt, also sind dann
irgendwann sind sie so ihr Studium Und das Modulkonzept in einer Programmiersprache bedeutet,
ich kann Bausteine der Programmiersprache, kann ich so anordnen,
dass sie nochmal ein eigenes, einen eigenen Sichtbarkeitsbereich bilden.
So, und das ist insbesondere so Sichtbarkeitsbereiche,
haben wir ja schon kurz drüber gesprochen,
was das so auf Klassenebene ausmacht, so der klassische Modulbegriff,
der definiert, also für eine Einheit in einer Programmiersprache,
eine Exportschnittstelle und die sagt dann aus, welche Operationen,
Typen und Konstanten sind von außen, von diesem Modul sichtbar.
Das impliziert, wenn ich also eine Exportschnittstelle,
Entschuldigung, wenn ich über eine Exportschnittstelle nachdenke,
ich brauche auch so etwas wie eine Importschnittstelle.
Die Importschnittstelle, die sagt, was ist denn das,
was ich haben möchte
Was von anderen Modulen exportiert wird, um meine eigene Dienstleistung zu implementieren.
So in einer ersten Näherung kann man jetzt so den klassischen Modulbegriff,
den kann man quasi eins zu eins,
kann man den so mit dem Klassenkonzept, kann man den vergleichen.
Wenn ich jetzt über Modul gesprochen habe und sie vor ihrem geistigen Auge,
haben sie das so mit dem Klassenkonzept abgeglichen.
Ja, das ist doch also hinreichend ähnlich. Ich weiß also,
es gibt einen Namensraum, der wird durch das klassische Modelkonzept
gefordert und der wird mit einer mit dem Klassenkonzept in objektorientierten Programmiersprachen wird,
der wird dieser Zugriffsschutz realisiert. Und auch,
dass hier so Elemente innerhalb eines Moduls sind verborgen, alles das,
was wir als Private beziehungsweise Protected-Deklatationen hatten für die unterschiedlichen Verwendungskonzepte,
das finden wir auch in Klassen wieder.
Und es gibt also einen gezielten Exportmechanismus, alles,
was ich als Public deklariere, in einer Klasse,
dass es eben nach außen hin sichtbar
In diesem Sinne sind Klassen, das,
was Sie bis jetzt kennengelernt haben, auch Module.
Aber ich habe ja schon gesagt,
also Klassen als einziges Konzept zur Schachtelung von Nicht-Schachtelung,
zur Strukturierung von großen objektorientierten Programmen, ist ein bisschen wenig.
Und da hat sich als Konzept, es ist nicht mächtig genug.
Also worauf ich jetzt hier nicht weiter eingehen werde,
ist, dass es innerhalb des Klassen auch ineinander geschachtelt werden können.
Also dass da nochmal Klassen in Klassen,
in Klassen deklariert werden können
Da ist das sinnvoll, ist aber für die Strukturierung von Programmen im Großen,
ist dieses Konzept, dafür ist es nicht gedacht und nicht geeignet. Es gibt,
und das ist das Konzept, was ich jetzt noch vorstellen wollte,
das ich jetzt noch kurz benennen wollte, das,
was sie implizit in Java auch schon kennengelernt haben,
was also so vergleichbar ist mit dem Modul-Konzept,
mit dem ursprünglichen Modul-Konzept, da sind die sogenannten Pakete,
Pakete, Packages,
deklarieren,
definieren,
einen eigenen Namensraum
Können nochmal so als Strukturierungseinheit, also größere Strukturierungseinheiten für objektorientierte Programme
verwendet werden. So wie sie das hier so schematisch sehen.
Sie können Klassen zu Paketen zusammenfassen.
Und dieses Paket bildet dann nochmal einen eigenen Namensraum.
Es gibt zum Export komme ich gleich noch,
diese Pakete
Lassen sich dann so von anderen Paketen, also von
anderen Klassen in anderen Paketen lassen, die sich verwenden.
Und sie sehen hier die Art und Weise, wie diese Verwendung typischerweise aussieht.
Das haben wir auch schon so hingeschrieben, haben sie das auch schon in ihren Programmen.
Hier sehen sie jetzt die volle Auflösung des Rätsels,
also dass sie das wahlweise qualifiziert importieren können oder sie können,
also mit dieser Sternchennotation, können sie so einen Rundumschlag machen.
Ich möchte alles importieren, was in diesem Package, some Package,
zum Export bereitsteht. Und wenn sie das importiert haben,
dann können sie eben diese, können sie auch diese verkürzte Schreibweise verkürzt,
also so wie sie hier dasteht,
also durch dieses Importanweisung im Vergleich, also zu dieser Darstellung,
zu dieser qualifizierten Darstellung, können sie das verwenden.
Das ist also der Import. Ein kleines Rätsel jetzt
vielleicht noch aufgelöst
Auch Pakete können ineinander geschachtelt werden. Und das findet also vielfache Anwendung.
Zur Strukturierung von sehr großen Systemen. Und das hier ist
jetzt hier auf dieser Folie steht jetzt, wie denn,
mit welcher Namenskonvention oder mit welcher Regel diese Pakete benannt werden.
Es ist nämlich umgekehrt zu der Art und Weise,
wie man einen Domänennamen im Internet bildet,
sodass man es also vom ganz Außen nach innen geht,
so wie sie das hier in dem Beispiel sehen
Von ganz außen, also die Top-Level-Domain bis hierhin und man kann das dann eindeutig, kann man einen Namen identifizieren. So,
jetzt nur noch ganz kurz zu der Stelle,
das ist jetzt der Cliffhanger auch, also für Fred,
wenn man nutzt, ist,
wenn man uns das mal so die gesamten Zugriffsmodifikatoren jetzt im Überblick anschauen,
sodass, wenn sie innerhalb einer Klasse innerhalb eines Paketes sind,
grün ist jetzt jeweils das, was sichtbar ist,
dann ist also eine private Methode in einer Klasse ist nur in dieser Klasse zugreifbar
Der Modifikator Default, den haben wir bisher so übersetzt mit,
ja, das ist, wenn da nichts steht,
dann steht da halt also public, dann ist das,
so, jetzt sind wir etwas schlauer.
Diese Aussage gilt innerhalb eines Paketes außerhalb eines Paketes,
also ist etwas, was nicht weiter qualifiziert worden ist,
nicht sichtbar. Das hier ist der Fall,
weswegen ich um 13 Uhr irgendwas noch Fred angerufen habe und sage,
sag mal Fred, die Folie legen wir jetzt seit drei Jahren auf oder vier Jahren Und wahrscheinlich,
also bevor es PowerPoint erfunden worden ist,
haben wir die auch schon aufgelegt, mit der Hand gemalt.
Aber stimmt das überhaupt? Das ist eine klasse außerhalb dieses Paketes
auf eine Protected-Methode einer Klasse in einem anderen Paket zugreifen kann.
Und dass diese Frage nicht völlig unberechtigt ist,
konnte ich aus der Antwort von Fred schließen,
der sagte, ich probiere das mal aus.
Ich sage jetzt nicht, was dabei rausgekommen ist.
So, und der letzte Fall Das ist ja unkritisch,
wenn also alles public ist, naja, dann ist die Paketgrenze auch irrelevant.
Also jedenfalls für den Zugriffsfall. So, damit sage ich
dann schönes Wochenende. Danke, dass Sie hergefunden haben.
Wir sehen uns demnächst wieder. Bis dann. Tschüss
Kann man mich wieder hören. Mir wurde ja ein anderes Mikrofon
versprochen letzte Woche, aber wir müssen auch heute nochmal so auskommen.
So. Ja. Habe ich schon eine Clips gestartet?
Ich glaube nicht. Ich will es nicht zweimal machen.
Nee, da ist es
Also ich hatte erst ein recht kompliziertes System für heute gebaut,
wo man so Wetterdaten übers Internet abfragen kann.
Und ich dachte so, hey, ich kann ja mal zwischendurch
mein Internet abklemmen, abklemmen und gucken, was dann passiert.
Aber das System ist so kompliziert geworden,
dass ich dachte, das kann ich euch nicht antun.
Wir machen stattdessen heute was anderes. Aber ich kann erst
mal den kleinen Cliffhanger von Guido machen.
Machen wir noch mal ganz kurz ein neues Projekt.
Java-Projekt. So, dann nennen wir das einfach mal egal.
Guido. Und dann können wir das doch jetzt einfach mal testen.
Ob man tatsächlich in einer Klasse Eine Protected-Methode machen kann,
nennen wir die mal Base-Class, also die Klasse,
von der man erbt.
Und da machen wir jetzt eine Protected-Methode,
nehmen wir sie M, Z-Ups, sehr kreativ.
Achso, vielleicht machen wir sie abstrakt. Oder nö,
ich kann sie auch implementieren. Es geht ja nur darum,
ob man sie irgendwie sehen oder benutzen kann.
So, das ist also das Paket Guido,
jetzt mache ich mal ein weiteres Paket.
Vielleicht nehme ich einfach mich
So. Und dann machen wir mal eine Klasse. Based,
die Rife nennt man die dann meistens. Die erbende Klasse
. Und jetzt erbe ich von Base und dann wird sich
eh Clips jetzt beschweren, dass er Base nicht kennt.
Warum nicht? Weil diese Klasse Base ja in einem anderen
Package liegt. Da gibt es jetzt zwei Möglichkeiten für,
die ungewöhnliche Möglichkeit ist, ich könnte jetzt einfach schreiben, guido.base.
Das macht aber eigentlich so gut wie keinen Java-Programmierer.
Die meisten Leute importieren diese Space stattdessen, die sagen,
ich möchte guido.base importieren aus dem anderen Paket
So, und jetzt ist die Frage,
ich kann jetzt ja hier mal irgendeine Methode machen, nenne ich sie X,
kann ich jetzt aus dieser Methode X das M aufrufen,
von Guido?
Ja, kann man machen. Das ist auch tatsächlich sinnvoll und nützlich,
das werden wir sehen, wenn wir über Entwurfsmuster reden und
das Beobachter muss da selber implementieren.
Ja, also alle Erben können tatsächlich protected Methoden aufrufen,
auch wenn diese Erben in anderen Paketen sind als die Basisklasse,
von denen man ab. Das war jetzt eine sehr technische Angelegenheit,
aber es wird in ein paar Wochen noch konkreter.
So, seht ihr irgendwas? Ja,
da muss ich ja mal eine Lehrzeitung noch machen
Genau. Also es gibt ja diese Folie,
wo so steht, früher war das ja alles so furchtbar
mit der Fehlerbehandlung und das stimmt, es war furchtbar.
Und das ist immer so ein bisschen wenig plastisch,
wenn man das einfach nur so auf einer Folie sieht.
Ich wollte euch das einmal so ganz kurz zwei,
drei Minütchen zeigen, wie man Fehlerbehandlung in C macht.
Da gibt es ja keine Exceptions im Java-Sinne.
Und dann habe ich gestern mal drei schöne kleine,
einfache Beispiele programmiert von halbwegs sinnvollen Programmen, die irgendwas Tolles machen.
Also zum Beispiel das erste Programm,
was wir dann programmieren werden, in Java mit Acceptions.
Da wird es darum gehen,
eine Datei so zu löschen, dass selbst wenn man sie
wieder herstellt,
nichts Sinnvolles mehr drin steht
Ich weiß gar nicht,
ob das heutzutage überhaupt noch geht mit den heutigen Festplatten,
aber wir tun einfach mal so, als ginge das.
Dann ein Programm, das einfach nur eine Datei in eine andere Datei kopiert.
Das ist quasi dasselbe, was ihr hier oben seht,
nur in Java übersetzt. Und wenn dann noch Zeit ist,
man weiß ja immer nicht, wie lange wir brauchen,
dann wollte ich mit euch mal ein Programm schreiben,
was eine Checksumme von einer Datei berechnet.
Das ist eigentlich auch mal schön sinnvoll,
solche Programme zu haben und zu verstehen, wie sie funktionieren.
Okay, und überall muss man mit Acceptions umgehen.
Gut. Also Fehlerbehandlung in C. Da muss ich einmal
kurz sehen, dass ihr alles seht.
Okay. Also ich werde euch jetzt nicht zäh beibringen,
aber ich will, dass ihr seht, so die Struktur.
Also sowas wie geschweifte Klammern und Simikola und Ifs
und so gibt es ja in C genauso.
Und wie man jetzt darauf reagiert, wenn irgendwas nicht klappt.
Das wollte ich einmal ganz kurz sagen
Also wir haben ja eine Funktion, man nennt das nicht Methoden in C,
sondern Funktion, lest das einfach mal als String.
Ich übergebe also einen String für den Namen der Datei,
aus der ich lesen will.
Und ich übergebe einen String für den Namen der Datei,
in die ich schreiben will. Gut, das sind jetzt
irgendwelche Typen, die könnt ihr auch nicht verstehen.
Das ist dann quasi die Datei an sich, nicht der Name,
sondern dass ich dann Zugriff darauf habe über das Betriebssystem.
Hier habe ich so einen kleinen Puffer, wo ich was drin abspeichern kann.
Das ist ein ERE. EREs kennt ihr doch auch aus Java
. Einfach ein ERE. Und das ist so was ähnliches
wie ein Int. So, und jetzt geht's los.
Ich will eine Datei öffnen, das könnte ja schiefgehen.
Vielleicht gibt es die Datei gar nicht oder ich darf sie
nicht öffnen oder die liegt irgendwo,
wo ich keine Zugriffsrechte habe oder so
Also diese Zeile Code sagt, ich möchte eine Datei öffnen.
Und zwar zum Lesen. Dieses R heißt, ich will lesen.
Und jetzt muss ich als nächstes prüfen mit einem IF, ob das geklappt hat.
Und das C-Programmierer schreiben gerne sehr kompakten Code. Diese Bedingung bedeutet,
wenn Saws die Neilreferenz ist,
also wenn ihr euch da mal die Dokumentation durchlest von F Open,
dann sagt euch die Dokumentation, hier kommt die Neilreferenz zurück,
wenn das Öffnen nicht geklappt hat.
Okay, ihr müsst also immer Dokumentation lesen,
wie werden Fehler überhaupt signalisiert? Manchmal über Returnwerte,
stand ich auch auf der Folie, manchmal über globale Variablen.
Okay, also wenn es irgendwie nicht geklappt hat,
dann gebe ich auf der Konsole aus,
dass ich
die Datei nicht öffnen konnte
Tja, und jetzt ist hier ein Goto.
Eieieiei, das machen wir in C ganz gerne.
Man springt quasi an das Ende, ans Ende der Funktion,
das sage ich euch einmal ganz kurz.
Man springt hier ans Ende der Funktion, könnt ihr das sehen, ja.
Es ist also, man konnte die Datei nicht öffnen,
dann ist auch nichts aufzuräumen sozusagen. Okay, also,
ja, man macht das aber tatsächlich so ein C, es tut mir leid.
Ich will euch ja die ganze Wahrheit zeigen und nichts als die Wahrheit.
Okay, wenn das jetzt aber geklappt hat mit dem Öffnung,
dann versuche ich als nächstes die zweite Datei zu öffnen und zwar zum Schreiben.
Das W heißt Schreiben. Und auch hier muss ich wieder gucken,
hat das denn jetzt geklappt? Vielleicht wollte die Datei in einem Verzeichnis anlegen,
wo ich kein Zugriffsrecht darauf habe,
vielleicht gibt es die Datei schon und sie ist schreibgeschützt,
könnte ja sein, dass es nicht klappt.
Dann muss ich also auf die Konsole schreiben, hey,
es hat nicht geklappt.
Und jetzt gehe ich zu einer anderen Stelle
im Code
Nämlich hierhin kann mir irgendeiner erklären, warum ich jetzt hier hingehen muss.
Also das Öffnen hat geklappt und das Schreiben klappt,
also ich kann es die zweite Datei nicht öffnen zum Schreiben.
Warum muss ich denn jetzt da hingehen? Warum kann ich
nicht einfach die Funktion beenden? Ist das irgendjemandem klar?
Ja. Genau, die Sorcertime wäre immer noch offen.
Ich muss also alle Schritte, die schon erfolgreich abgearbeitet habe,
die mit dem Dateisystem zu tun haben,
die muss ich wieder rückgängig machen.
Ja. Nevermind, alles klar, das verstehe ich.
Nevermind verstehe ich. Okay, das heißt also,
wenn wir hier angekommen sind, wissen wir beide Dateien wurden geöffnet,
wunderbar, dann können wir doch mal loslegen zu kopieren.
Gut,
wie kopieren wir denn jetzt
Das ist einfach eine Wild-Schleife. Ich sage hier,
ich möchte was einlesen. Wie gesagt,
ihr müsst nicht alles verstehen, was hier steht.
Einfach nur die Grundstruktur. Ich möchte was einlesen. Und
solange ich mehr als null Buytes eingelesen habe, tja,
das könnte ja sein, dass es nicht funktioniert hat.
Irgendein blödes Problem, Festplatte kaputt oder jemand hat den Stecker
rausgezogen oder so. Und jetzt muss ich, ja,
global abfragen, ob mein Saw-Stream in einem Fehlerzustand ist.
Und wenn er in einem Fehlerzustand ist,
schreibe ich das auf die Konsole und gehe dann an eine Stelle,
die dafür sorgt, dass beides geschlossen wird.
Das seht ihr dann hier
Ja. Okay, wenn das Lesen geklappt hat,
dann schreibe ich und dann muss ich gucken,
möglicherweise hat beim Schreiben ja irgendwas nicht funktioniert.
Ihr seht also, das ist eine andere Konvention.
Hier liefert das Effright also nicht irgendwie einen Fehlercode zurück,
sondern ihr müsst eine andere Funktion aufrufen,
um zu fragen, ob es einen Fehler gab.
Also ihr seht schon die Hälfte von dem Code oder sogar noch mehr.
Geht hier ja nur darum, Fehler zu behandeln.
Der eigentliche Algorithmus öffnet die Dateien, lies und schreibt,
solange das irgendwie nicht vorbei ist.
Das ist hier irgendwie ziemlich gut versteckt zwischen diesen ganzen Ifs.
Ich habe also tatsächlich vier verschiedene Ifs nur für Fehlerbehandlung,
wenn ich mir nicht verzählt habe.
Und dann diese Go-Tos und so,
ach,
Okay, ich glaube, ich schließe das einfach mal ganz schnell wieder.
Zack. Nee, das hat gespeichert. Ich schließe es
jetzt einmal. Okay. Das war also das,
wie gesagt, ganz kurz, dass man mal gesehen hat,
wie furchtbar es wirklich mal war.
Und jetzt kümmern wir uns um Java. Wir sind ja
hier in einer Java-Veranstaltung. Wir wollen also jetzt ein Programm schreiben,
womit ich eine Datei, ja,
im Prinzip mit Nullen überschreibe und dann erst lösche.
Mehr heißt es eigentlich nicht. Okay,
dann machen wir uns doch mal hier ein neues Projekt.
Nennen wir das doch mal safe, Deal Lead oder so
Und dann fügen wir da mal was hinzu.
Eine neue Klasse. Ja, ich bin ja immer nicht
so wahnsinnig kreativ, nennen wir es. Ich will es
ja nachher auch von der, ich nenne es einfach Main.
Vielleicht fällt mir später was Besseres an,
man kann sich immer ganz gut umentscheiden in Eclipse.
Okay. Auf dem Aufgabenblatt werdet ihr ein oder zwei Funktionen kennenlernen von Java,
mit denen man so schöne kleine Fensterchen aufploppen kann.
Und das wollte ich ihr euch auch einfach mal zeigen.
Ich habe mir dazu extra mal im Browser ein paar Bookmarks
gesetzt, damit ich das nicht vergesse.
Wie die hießen. Ah ja, genau, der J-File-Shooter.
Also ich kann mir einen Hast du,
vielleicht sollte ich erstmal eine Methode öffnen?
Ja, ich kann mir also einen File-J-File-Schuhsaal erzeugen.
Der muss erstmal importiert werden. Okay. Den will ich
in eine neue lokale Variable speichern. Ja, der Name
ist vielleicht ein bisschen lang, nennen wir das mal Shoeser.
So. Und diesen Shoeser möchte ich jetzt irgendwie anzeigen.
Wie mache ich das denn? Hallo, liebes Auto,
da ist es. Show Open Dialog,
das nehmen wir doch mal
Und da übergebe ich jetzt einfach Neil,
weil ich ja gar keine grafische Anwendung gerade habe,
in die das eingebettet wird.
Nur diese beiden Zeilen Code will ich jetzt mal mit euch ausführen,
damit ihr mal seht, was da passiert.
Sag ich mal, hier, Ron as Java Application.
Ja, ich versuche mal, mich mit meiner Begeisterung zurückzuhalten.
Aber diese beiden Zeilen Code haben tatsächlich mir so ein Fenster
geöffnet oder ich kann jetzt hier irgendwie durch mein Dateisystem durchgehen und so weiter.
Ich kann die auch abbrechen oder öffnen.
Das macht jetzt natürlich, das macht noch nichts.
Also wenn ich jetzt hier auf Öffentlichkeit lege,
passiert überhaupt nichts
Weil ich ja noch gar nicht auswerte, was der nächste Benutzer gedrückt hat.
Und auch das ist hier relativ einfach, das ist noch
gar nicht so kompliziert, wie es später mal werden wird.
Dieses Show Open Dialog liefert euch einfach was zurück.
Wir gucken mal ganz kurz, was es uns zurückliefert.
Ich habe ja für meine Java-Dog-Perspektive, da kann man doch
so wunderbar lesen, dass sie das alle lesen könnt.
Genau. Also hier sieht man sehr schön, es kommt
ein Returnwert zurück, sobald er benutzt oder was klickt.
Also man kann gucken, hat er auf den Cancel-Button gedrückt
oder hat er gesagt, ja, ich will das machen.
Und Arrow-Option, okay, wahrscheinlich, wenn irgendjemand auf das Kreuz
oben klickt oder so. Also ich kann ja mal gucken,
ob der Benutzer auf diese Approve-Option geklickt hat,
ob er wirklich was machen will
Das kann ich ja so einfach, ja,
ich muss es jetzt hier in der Variable speichern.
Was ist denn da der Typ? Kann ich hier sagen,
speicher mir das meine Variable? Also es ist ein Int
. Dann nennen wir das doch mal Choice. Okay,
und jetzt kann ich einfach prüfen, welcher dieser Choices war es denn,
war es, und wie hieß das jetzt, J-File-Shoozer.
Approve, da ist es. Okay,
jetzt mache ich mal diesen Bereich wieder ein bisschen kleiner,
das nervt ja, wenn da hier so viel Platz wegnimmt.
So, ich habe noch gerade weggeschoben, warum ist jetzt schon wieder da?
Zack. Okay. Das heißt, wir landen hier drin,
wenn der Benutzer sich in der Datei ausgesucht hat,
gesagt, okay, die will ich jetzt haben.
Ansonsten eben nicht, wenn ich jetzt Karlsruhe drücke,
passiert nichts.
Woher weiß ich denn jetzt, welche Datei er sich ausgesucht hat?
Vielleicht kann ich ja diesen Chooser das fragen. Gibt es hier sowas wie,
ach guck mal, die erste Option ist es schon.
Und Eclipse glaubt sogar mit einer Wahrscheinlichkeit von 100 Prozent,
dass ich diese Methode brauche, dann nehmen wir die doch mal.
Okay, die spare ich euch mir wieder in der Variable.
Das ist also das Pfeil, was elected wurde,
das ist ein bisschen lang, ich nenne das einfach nur mal Pfeil.
Und jetzt kann ich im Prinzip mit diesen Pfeilen machen,
was ich will. Diese Datei ist noch nicht offen.
Diese Datei ist einfach nur, wie versuche ich das mal zu erklären?
Also es ist ein bisschen mehr als ein String.
Es ist nicht nur die Angabe, wie die Datei heißt oder so.
Ich könnte die Datei jetzt auch fragen, hey,
wie groß bist du oder welche Zugriffsrechte gibt es auf dir oder so.
Wollen wir mal ganz kurz gucken,
was man damit so machen kann
Genau, also Get Name, Get Path, X. Ich kann fragen,
ob es die Datei überhaupt gibt und so weiter.
Okay. Gut. Und es gibt viele Java-Klassen,
die mit solchen Files umgehen können. Ich kann zum Beispiel
jetzt eine Java-Klasse mir instanzieren, die sagt,
ich will auf Files was schreiben können zum Beispiel,
genau das will ich ja tun.
Dazu habe ich mir auch mal wieder hier die API,
weil ich kann mir nie merken, diese furchtbaren Klassen heißen,
File Output streamen, das war das.
Genau, ich kann mir also einen neuen File Output streamen machen.
Das muss wahrscheinlich erstmal wieder importiert werden, genau.
So. Und das soll wieder in eine Variable gespeichert werden.
Kann ich
das irgendwo machen hier
Wieso heißt das immer so komisch? Ich glaube, ich
drücke aus Versehen auf die Raute. Nennen wir das mal out.
Okay, ich habe jetzt also einen Output-Stream mehr erzeugt.
Tja, und jetzt ist irgendwie was komisches.
Warum beschwert sich denn jetzt Eclipse? Achso,
vielleicht hättet ihr dieses Pfeil noch einstecken sollen. Das könnte
ein Grund sein. Aber Eclipse beschwert sich immer noch.
Und das hat jetzt mit diesen Exceptions zu tun,
wenn ich hier einfach mal raufhalte, würde mir Eclipse sagen,
anhandelt Exception Type, Fire Not Found Acception.
Okay, es könnte also sein, dass das Öffnen nicht klappt,
weil es die Datei zum Beispiel gar nicht gibt.
Ja. Okay
Ja, jetzt haben wir im Prinzip zwei Möglichkeiten. Ich kann jetzt entweder sagen,
ich will die Fehlerbehandlung hier in diesem Code machen,
das mache ich erst mal der Einvergertabe,
weil das eben das Einfachste ist.
Dazu sagt man also dieses Try,
das hat der Guido euch ja erklärt, man kann versuchen,
Code auszuführen und vielleicht klappt es ja nicht, dann catcht man.
File not found acception hat er ja, glaube ich, gesagt.
So. So, jetzt muss ich das wieder importieren, zack. So,
okay, das heißt, ich werde also hier drin landen,
wenn es diese Datei zum Beispiel nicht gibt,
ich werde da jetzt noch nichts Sinnvolles reinschreiben.
Gut,
was haben wir denn noch
So, ich habe jetzt also Zugriff auf diese Datei
und ich will da jetzt was reinschreiben.
Wie schreibe ich denn was in der Datei rein?
Ich könnte einfach mal so ein bisschen hier ausprobieren mit der
Punktnotation, was er mir so alles anbietet.
Ah, guckt mich jetzt zum Beispiel. Wenn ich also
irgendwie eine RE vorbereitet habe mit irgendwelchen Bytes da drin,
im Idealfall null Bytes oder irgendwelche Zufallsbytes,
dann kann ich die einfach in die Datei reinschreiben.
Vielleicht sollten wir uns erst mal merken, wie groß die
Datei überhaupt ist. Kann ich nicht sagen, Pfeil.längs?
Genau. Das will ich in eine Variable tun. Ja,
ich nenne es mal Len, dann ist es nicht
so lang, wieso hat das wieder umbenannt?
Das wollte ich nicht. Ich wollte lennen, lenden
Okay. So, und dann machen wir uns auch
ein RA mit Nullen drin. Das Einfachste wäre jetzt,
wenn ich das einfach genauso lang mache wie die Datei.
Das könnte aber ein Problem sein, weil das,
weil RA ist möglicherweise gar nicht so lang sein dürfen.
Okay, ich mache ein kleineres RA.
Wie macht man denn nochmal ein RA in Java?
Weiß das noch jemand? Obwohl das Programmatic Touch schon war
und die alles schon wieder vergessen hat möglicherweise?
Ja. Genau, wir brauchen erstmal den Datentyp dann,
die Ecke in Klammern. Dann nenne ich das mal Buffer
, ja.
Byte, so
Nehmen wir mal 1000. So. Fehlt da noch irgendwas? Ja.
New fehlt, genau. Keine Objekte erzeugen ohne New.
Und Eric sind ja auch irgendwie so objektartig in Java.
Okay. Und ich muss das nicht initialisieren,
da sind standardmäßig Nullen drin in Java.
Das ist irgendwie auch ganz nett. Okay. Ja,
wie viele Bytes muss ich denn jetzt da reinschreiben?
Also wenn wir, ich könnte ja immer wieder diese 1000
Bytes reinschreiben und irgendwann wird am Ende was übrig bleiben.
Ich könnte erst mal gucken, muss ich überhaupt noch 1000
Bytes reinschreiben? Also solange die Länge größer oder gleich,
ich sag mal größer, die Länge von dem Buffer ist,
ist, ist, dann schreibe ich das doch mal rein.
Also sage ich, hey, lieber auch putzen,
ich will was schreiben, nämlich diesen Buffer.
Da hat er diesen Overload genommen, den ich gar nicht brauchte.
Und dann dekrementiere ich einfach mal die Länge um Buffer.lenk. Also ich,
ja, ich subtrahiere quasi immer weiter von der Länge,
bis ich dann irgendwann unter diese 1000 komme.
Oh, jetzt gibt es ein Problem. Warum könnte es jetzt
ein Problem geben? Wir hatten ja hier oben gesehen,
hey, möglicherweise gibt es die Datei gar nicht,
darauf muss ich reagieren.
Jetzt versuche ich zum ersten Mal was reinzuschreiben in die
Datei und Eclipse
ist irgendwie unzufrieden
Tja. Das könnte einen Fehler geben, genau. Wir gucken mal,
was er glaubt, was für einen Fehler das geben könnte.
Unhändelt, Acception Type, IO-Acception. Aha. Also irgendwie
Eingabefehler auszulösen. Tja, was machen wir denn jetzt?
Jetzt gibt's mehrere Möglichkeiten. Ich könnte zum Beispiel hier
einen weiteren Catchblock reintun. IO-Acception. Und jetzt passiert was
total Lustiges hoffentlich. Also ich muss es importieren.
Danach passiert was Lustiges.
Hm. Also das ging doch eben noch. Habe ich
jetzt irgendwas kaputt gemacht? Wir schauen mal kurz, was
die Fehlermeldung sagt. Unreachable Catch-Block for fine out Found Acception.
It is already handled by the catch-block for iO exception.
Aha. Also wenn wir uns mal die Typhierarchie angucken,
also Acceptions sind ja ganz normale Klassen von zur Laufzeitobjekte,
dann seht ihr, dass die File not Found Acception erbt von der IO Acception.
Und Acception Handling ist halt so definiert, sobald in dem Triblock,
in diesem Triblock irgendwo ein Fehler auftritt,
dann wird halt einfach der Reihenfolge nachher geguckt, okay,
ist es eine IO-Acception, falls ja, kannst du hier reinspringen und den Rest ignorieren.
Falls nicht, prüf doch mal den nächsten Acception-Typ.
Und da jede File not Found Acception auch eine IO-Acception ist,
wird dieser Catchbock garantiert niemals ausgeführt werden
Man könnte es zum Beispiel umdrehen, genau. So, ne? Dann kann ich also,
ja, hier eine Spezialfehlermeldung ausgeben,
wenn die Datei nicht gefunden wurde oder hier eine Spezialfehlermeldung,
wenn es beim Schreiben ein Problem gab,
müsst ihr euch jetzt einfach entscheiden,
wollen wir dafür zwei verschiedene Fälle haben?
Oder wir sagen einfach, ach, wisst ihr was,
wir haben hier nur 45 Minuten.
Ich catche einfach alle IO-Acceptions. Mir ist das egal,
ob das daran liegt, dass die Datei nicht gefunden wurde
oder dass es irgendwas anderes ist.
Das reicht mir jetzt erstmal. Ich will es erstmal nicht
zu kompliziert machen. Wir können da eigentlich auch ruhig mal
was reinschreiben. Ich kann da irgendwie reinschreiben,
Probleme beim Schreiben in die Datei oder so.
Dass der Benutzer zumindest irgendwas sieht
Okay. Gut, wir waren also zuletzt stehen geblieben mit
unserer eigentlichen Logik bei dieser Schleife.
Wir zählen also diese Länge immer weiter in tausender Schritten runter,
bis wir irgendwann bei tausend angekommen sind oder unter tausend sind.
Und dann müssen wir jetzt auch den verbleibenden Rest reinschreiben.
Dafür gibt es einfach eine Überladung von Ride. Da sage
ich dann einfach, Buffer, und dann kann ich weitere Argumente angeben.
Genau hier. Also ich kann sagen, wir fangen an
bei null und bitte die verbleibende Länge noch einschreiben.
Ist das jetzt ein Problem als ein Typfehler, oder?
Kann das sein, dass Längen zu lang ist?
Da erwartet ein Int. Okay, ich muss jetzt also
casten, erinnert ihr euch noch an Typ Typ Casts?
Gut. Wisst ihr was? Ich mache einfach mal Folgendes,
damit ihr versteht, wie das genau funktioniert,
gebe ich hier nochmal auf die Konsole aus,
welchen Wert längst gerade hat.
Längs ist jetzt nur noch hups. Dass euch irgendwie klar ist,
wie oft diese Schleife durchläuft. So. Okay. Gut,
das heißt also, wenn wir an dieser Stelle angekommen sind,
haben wir die ganze Datei mit Nullen überschrieben und jetzt können wir sie eigentlich löschen.
Da sage ich dann einfach mal Pfeil, Punkt.
Ich glaube, man kann sie irgendwo löschen,
da ist es auch schon.
Achso, und das liefert ein Bulien zurück.
Aha,
warum das denn
Das ist ja witzig, das funktioniert also nicht mit Acceptions,
das war mir gar nicht so bewusst.
Okay. Das Problem ignoriere ich jetzt erst mal.
Okay, ja, wollen wir das Programm mal ausprobieren?
Wir probieren es einfach mal aus. Ich starte es,
ich mache das erst mal zu, das ist nicht mehr so interessant.
So, jetzt finden wir hoffentlich eine Datei,
die ich nicht mehr brauche.
Ich habe vorhin extra aufgeräumt, das ist ja blöd.
Vielleicht hätte ich mal irgendeine, ich breche das mal ab.
Wir machen uns mal irgendwelche Dateien, die wir gar nicht brauchen.
Was haben wir denn hier mal so,
Ach, die könnte ich ja mal kopieren mit meinem
wunderbaren Kopierprogramm, was ich vorhin geschrieben habe.
Also franz.txt kopiere ich meinen Kopie.txt. So ist sie jetzt da.
Da ist die Datei. Wir können auch mal reingucken,
ob es auch wirklich da ist. Genau. Okay.
Kennt jemand diesen Text? Okay, das ist ein deutscher Satz,
der alle 26 Buchstaben enthält und möglichst kurz ist.
Gut. Okay, das will ich jetzt also löschen.
Ich starte unser Programm
Nee, ich breche es sofort wieder ab, denn das
mit den tausend wird man ja gar nicht hier sehen.
Ich nehme mal nur zehn. Die Datei ist ja so
klein. Dann würde die Schleife gar nichts Spannendes machen.
So, also ich will die Kopie löschen. Punkt,
das funktioniert. So, man sieht jetzt erstmal nichts,
also keine Fehlermeldung, das ist ja schon mal ganz nett.
Gucken wir mal ganz kurz, ob sie jetzt weg ist.
Ja, sie ist tatsächlich weg. Und ja,
es gibt jetzt keine Möglichkeit zu prüfen,
ob sie wirklich mit Nullen überschrieben wurde oder nicht.
Also irgendwelche Daten, Sicherheitsexperten soll ich euch mal meine Festplatte ausladen.
Ihr könnt gucken, ob ihr die Daten noch wieder herstellen könnt.
Ich glaube, das wird nicht möglich sein.
Was ich euch für die Übung auch noch zeigen wollte,
ist, jetzt kriegt man also so ein schönes, grafisches Fenster,
wo man sich die Datei auswählt, die man überschreiben will.
Und wenn es nicht klappt, dann kommt auf der Konsole
so eine Fehlermeldung. Das ist ja irgendwie nicht so schön.
Kann man hier nicht auch was Schönes, Grafisches aufmachen.
Und dazu zeige ich euch auch mal, dass es sowas gibt.
Das sollte ich in der Übung nämlich auch benutzen.
Das heißt, hier haben wir es. Genau. Also
es gibt in der Klasse, kann man das hier umsehen?
Nee, kann man gerade nicht sehen. In der Klasse
J Option Pain, da seht ihr es,
gibt es eine Methode, die heißt Show Message Dialog.
Hier ist sieben
Genau. Und hier könnt ihr, ja, da übergebt ihr
einfach wieder nall, das steht auch auf dem Aufgabenblatt.
Und da kann man eben irgendeine Fehlermeldung ausgeben,
dann kriegt ihr die schön mit so einem grafischen Fenster aufgeploppt.
Das versuche ich doch mal mit euch zusammen zu machen.
Also, J. Option Pain, Show, Message Dialog,
da ist er. Wir haben keinen Parent. Und jetzt
kann ich ja zum Beispiel sagen, was hatte ich denn vorher gesagt?
Konnte nicht in die Datei reinschreiben oder so.
So, ich glaube, sowas hatte ich irgendwie gesagt.
Wie kann ich denn jetzt dafür sorgen, dass diese Fehlermeldung
auch tatsächlich kommt? Aber du hast schon eine Idee,
irgendjemand, der vielleicht noch nicht sich gemeldet hat heute
Keiner? Ja, dann gerne. Ah, das probiere
ich mal aus. Also gibt es die Kopie noch?
Nee, ne? Dann mache ich sie mal kurz wieder.
So, ist jetzt die Kopie da, ja.
Also du meinst, ich starte jetzt das Programm?
Hier ist die Kopie. Und jetzt gehe ich erstmal in
die Konsole und lösche die Kopie.
Ich weiß es nicht
Ah, guck mal, hier ist sie noch.
Okay, dann sage ich jetzt mal öffnen.
Irgendwie ist jetzt gar nichts passiert, hallo? Ach so,
möglicherweise hat er gemerkt, dass wir ihm das irgendwie...
Es ist nichts passiert. Das ist ja merkwürdig. Okay,
dann müssen wir die Variante nehmen, die ich mir überlegt hatte.
Wir können dir einfach mal Schreib schützen. Ich sage einfach,
die Kopie, bitte Schreibschützen, ja,
also minus W heißt nicht mehr schreibbar.
Das müsst ihr mir jetzt einfach mal glauben.
So, jetzt hoffe ich mal, Demonstrationseffekt,
dass das jetzt wirklich funktioniert.
Ich will
die Kopie löschen und
Ah, konnte nicht in die Datei reinschreiben, das hat funktioniert.
Okay, und wenn das nicht geklappt hätte, dann hätte ich einfach Folgendes gemacht.
Ich wäre gar nicht in meinem Home-Fahrzeugnis geblieben,
sondern ich wäre mal so ein bisschen ins Hauptverzeihnis gegangen,
vielleicht irgendwie, was weiß ich, hier vielleicht.
Sie ist hier nicht irgendwo Java oder so?
Ach, On-Sip, das benutze ich sowieso nie.
Ah, guck mal, Glück gehabt. Da habe ich einfach
nicht die Rechte als Benutzer in so eine Systemdatei reinzuschreiben,
ja, das ist doch irgendwie ganz nett.
Okay, gut, kriege ich also eine vernünftige Fehlermeldung. Ja,
und was ich irgendwie ganz nett finde, ist tatsächlich,
dass die gesamte Fehlerbehandlung im Prinzip, ja,
Hier in diesem Catches und ich musste halt noch dieses Try schreiben, okay.
Aber ich musste nicht hier prüfen, hey,
hat das eigentlich geklappt, diesen Stream zu öffnen?
Hey, hat das eigentlich geklappt, da reinzuschreiben?
Hey, hat das eigentlich geklappt, hier reinzuschreiben?
Okay, und hier müsste ich es eigentlich theoretisch prüfen,
weil das ja die Symbolien zurückliefert.
Das vergessen wir jetzt einfach mal. Das finde ich irgendwie
ganz nett. Also hier ist der sogenannte Happy Path und
wenn irgendwas zwischendurch nicht funktioniert, ist hier dann die Fehlerbehandlung.
Ja, gibt es dazu noch Fragen bis hierher?
Okay, dann wollte ich euch noch mal zeigen.
Die Methode ist ja ganz schön lang, ne?
Vielleicht können wir ja mal, tja,
wollen wir einfach mal den ganzen Try-Blog in meine eigene
Methode packen
Das können wir doch einmal machen, oder?
Ich nehme diesen ganzen Triblock. Was müsste,
was müsste ich denn in die Methode reinreichen?
Wisst ihr, was irgendwas noch komisches ist? Hier wird
irgendwas gelbe unterstrichen. Oh, out is never closed.
Das haben wir ganz vergessen. Das sollten wir vielleicht mal
machen. Das ist ja interessant, dass ihr Clips dafür
schlau genug ist. Okay. Gut. Ich glaube,
ich schreibe die Methode erstmal hier unten irgendwo.
Also eine kleine Hilfsmethode könnt ihr die noch sehen.
Mir fällt gerade
nichts Sinnvolles ein
Und wenn ich den Code jetzt da einfach reinschiebe,
dann muss ich ja sicherlich das File-Objekt übergeben,
sonst weiß man ja gar nicht,
mit welchem Fall er umgehen soll.
Also ich brauche einen Parameter. So, ne?
Seid jetzt zufrieden? Ach, den Buffer. Den Buffer
können wir uns ja eigentlich, wisst ihr was,
das nehme ich mal alles mit hier runter.
Das ist ja außerhalb gar nicht interessant. So, okay.
Gut, jetzt kommen wir nämlich zu einer spannenden Sache.
Vielleicht ist man hier oben, das ist eigentlich noch spannender.
Oder einfacher zu erklären. Der Compiler beschwert sich jetzt,
dass in diesem Triblock nirgendwo eine iOcception auftreten kann.
Also ist es eigentlich Quatsch,
dass es
diesen Catchblock gibt
Seht ihr das? Unreachable Catch. Ähm... Das ignorieren wir
jetzt erstmal. Jetzt sind hier unten auch schon wieder Fehlermeldungen.
Also hier beim Öffnen, beim Schreiben, beim Schreiben, beim Schließen.
Warum sind denn jetzt hier Fehlermeldungen sich? Vielleicht muss ich
das einfach aufrufen. Ich rufe das jetzt mal auf.
Helper und übergebe Pfeil. Ist jetzt der Compiler schlau genug
zu verstehen, naja, wenn du diese Methode aufrufst,
dann schaue ich mir mal den Code da unten an.
Ach, da fliegen ja IO-Acceptions ohne Ende,
aber kein Problem, die catcht du ja hier.
Nee, so funktioniert der Compiler offenbar nicht. Der Compiler
guckt sich also die Methoden erstmal ganz isoliert voneinander an.
Sieht hier eine Methode, wo diverse IO-Acceptions uns um
die Ohren fliegen können und wir machen nichts damit
Ich will aber auch an dieser Stelle gar nichts damit machen.
Ich will tatsächlich, dass der Catchblock hier oben ist.
Habt ihr eine Möglichkeit kennengelernt zu sagen?
Diese Methode kümmert sich nicht selber um die Exceptions,
sondern reicht sie an den Aufrufer weiter.
Irgendjemand sonst noch, oder? Ja. Throws, genau
. Das war so dieses andere Schlüsselwort.
Ich kann das hier oben reinschreiben.
Throws,
IO Accept
Sicher, jetzt ist alles, alle Probleme sind jetzt beseitigt.
Also hier ist der Compiler zufrieden, okay,
hier könnte zwar eine IO-Exception auftreten, aber ich dekariere ja an meiner Schnittstelle,
dass es tatsächlich passieren kann, beziehungsweise diese Methode tut das.
Und jetzt versteht der Compiler auch, naja,
diese Helper-Methode, da sehe ich ja rein statisch,
also in der Signatur kann ich ja nachgucken, ah,
die schmeißt theoretisch so eine IO-Exception oder könnte sie schmeißen,
dann muss ich mich auch darum kümmern.
Ja, das heißt, wenn ihr das irgendwie weglassen würdet,
wenn ihr sagen würdet, ich tue das mal außerhalb des Trike-Hatchs,
dann wird er sich hier sofort wieder beschweren und sagen,
nee, nee, nee, nee,
nee,
hier könnt ihr ja eine IO-Exception auftreten und du kümmerst dich gar nicht darum.
Sehr guter Punkt. Ich weiß nicht, ob es alle verstanden haben.
Also, Inside 35 öffnen wir eine Datei und in Zeile 43
schließen wir diese Datei wieder. Aber es könnte ja sein,
wenn es zum Beispiel hier eine IO-Exception auftritt,
weil vielleicht die Festplatte voll ist oder so.
Oder hier könnte auch eine iO Acception auftreten.
Dann kehrt der Kontrollfluss ja sofort zum Aufrufer zurück. Also,
es ist tatsächlich so, wenn hier eine Acception auftritt,
dann wird aus der Schleife rausgegangen und aus dieser Methode wird auch rausgegangen, sofort.
Alle Kurzzahlen, die da drunter stehen, werden nicht mehr ausgeführt.
Insbesondere nicht das Schließen der Datei
Oh, eieieiei, was machen wir denn jetzt?
Das ist ja blöd. Kennt ihr ein Sprachkonstrukt,
was sagt, es soll auf jeden Fall am Ende etwas passieren?
Ja. Finally. Richtig. Das heißt,
wir brauchen jetzt hier doch wieder irgendwie einen Try.
Wo baue ich das denn jetzt mal sinnvollerweise ein?
Vielleicht hier. Ich könnte also, oh Gott,
das wird jetzt lustig. Aber wir haben ja Zeit,
das ist ja kein Problem. Dann komme ich halt zu
den anderen Beispielen nicht mehr, das macht ja nichts.
Also ich will das alles tryen und ich will am Ende
etwas machen, bringt das ohne Catch.
Ja, das heißt, das Close, wird es dann,
ist das schlimm, wenn ich das nach dem Delete mache?
Ich weiß es ehrlich gesagt nicht. Ich glaube,
die Lied klammere ich jetzt einfach mal aus,
damit es die Diskussion nicht zu kompliziert macht.
Okay, der Compiler beschwert sich jetzt hier,
weil es die Variable Out gar nicht gibt an dieser Stelle.
Ja, das hat was mit Sichtbarkeitsbereichen zu tun.
Die Variable Out, deklariere ich ja in diesem Blog,
also gibt sie auch nur in diesem Blog.
Ja, ich muss also die Deklaration dieser Variable,
muss ich jetzt einfach mal hochziehen. Also ich muss sagen,
okay, ich deklariere die Variable hier oben und ich initialisiere sie hier drin.
So, jetzt haben wir ein weiteres Problem,
was ist denn jetzt das Problem?
Ach, das ist toll, ein Problem gelöst,
das nächste kommt
Main ot have been initialized. Ah. Ja,
Tatsache. Also tatsächlich, wenn dieses Öffnen fehlschlägt,
dann habe ich ja nie einen Wert in diese Variable Out reingeschrieben.
Und das ist in Java nicht erlaubt,
Variablen zu benutzen und die noch nicht was reingeschrieben wurde.
Ja, ich muss jetzt also hier irgendeinen blöden Dummy-Wert reinschreiben.
Was nimmt man denn daran? Was ist so ein Standardwert
für eine, ja? Nein, genau. So,
jetzt muss ich natürlich höllisch aufpassen. Ich kriege jetzt hier
eine Night-Pointer-Acception, wenn ich das einfach so mache.
Das heißt, ich muss jetzt erst mal gucken,
ob da auch wirklich kein Nall drin ist.
Boah. Das ist ganz schön kompliziert, oder
Wir haben jetzt Glück, dass wir hier diese IO-Acception schmeißen.
Also normalerweise müsste man sich noch darum kümmern,
dass dieses Close ja auch wieder fehlschlagen könnte und das auch wieder in einen Trike-Catch reintun.
Das müssen wir jetzt in diesem Spezialfall zum Glück nicht machen.
Aber ich zeige euch einmal, wie es aussehen würde.
Man würde dann in dem Finally, nee, jetzt habe ich mich irgendwie verklickt.
Man würde in dem Finally sagen, ich mache einen neuen Trike-Catch-Blog.
So. Und da muss ich die IO-Acception irgendwie catchen oder so.
IO-Acception. Tja, und jetzt ist die Frage,
was macht man denn jetzt sinnvollerweise? Irgendwann hat man festgestellt,
wenn das Schließen einer Datei fehlschlägt, dann kann man eigentlich nichts Sinnvolles mehr machen.
Dann kann man eigentlich nur noch die Hände in die Luft werfen und sagen,
okay, ich habe alles versucht, was man machen konnte.
Es ging einfach nicht. Und ihr könnt euch vielleicht schon vorstellen,
das hat man also ungefähr 15 Jahre lang so gemacht in
Java und hat dann irgendwann festgestellt, also dieses Ziel,
das möglichst wenig Code sich um Fehlerbehandlung kümmert,
ist hier irgendwie nicht wirklich erreicht, oder?
Also ich meine, dieser ganze Code kümmert sich ja
nur darum, dass die Datei geschlossen wird.
Das ist irgendwie nicht so schön. Ich versuche das jetzt mal
so weit zurückzuzubauen, dass es wieder einigermaßen so aussah wie vorher.
Also wir hatten das Outpunk Close, glaube ich,
hier, richtig.
Und dieses Finaly gab es nicht
Und dann brauchte ich auch diesen zusätzlichen Tribe-Block nicht mehr.
Ich hoffe mal, dass es jetzt wieder einigermaßen so ist,
wie es mal war. Ja, keine Ahnung. Ich
glaube, ich lösche diese Zahl erstmal. Ich will nicht,
dass ihr uns irritiert. So ungefähr war es auch vorher,
ne? Genau. Und wir hatten dann festgestellt, hey,
wenn ich die Datei hier öffne, dann kann ich ja nicht sicherstellen,
dass diese Zeile definitiv auf jeden Fall ausgeführt wird.
Okay. Ja, und die Lösung, die man
dafür irgendwann mal gefunden hat, ist eigentlich total super.
Also, man kann... Dafür gibt es eine neue Sonntagsmarke,
man nimmt mal wieder einen Tribe, aber das ist jetzt ein ganz besonderer Trial.
Ich kann jetzt Dieses Öffnen der Datei, direkt in Runde klammern,
ach so, hinter das Try schreiben.
Ich sehe schon, ich habe euch gerade
ganz viel kompliziertes Zeug gezeigt und jetzt wird es endlich einfach.
Einigermaßen. So, das ist also eine neue Syntax,
die es seit Java 7 gibt.
Java 7 ist fünf Jahre alt, glaube ich, ungefähr.
Ich sage also mit dieser Syntax-Liebes Java, versuch doch mal,
diese Datei zu öffnen. Und wenn es nicht klappt,
dann haben wir eben Pech gehabt, okay, dann kann man nichts,
ja, dann fliegt diese ganz normale IO-Acception, okay,
aber sie muss nicht geschlossen werden, wenn es nicht klappt.
Aber wenn das Öffnen geklappt hat,
dann führ doch mal diesen ganzen Code hier aus
Und das Spannende ist jetzt, dass sie wir das schließen,
nicht mehr selber dahinschreiben müssen. Ich habe das jetzt mal extra auskommentiert.
Es ist also quasi so in der Sprache Java definiert.
Wenn dieser Triblock komplett durchgelaufen ist,
dann wird Close automatisch aufgerufen auf der Variablen,
die wir in den runden Klammern hinter den Triy hingeschrieben haben.
Tja, das heißt, ich kann es nicht vergessen,
dahin zu schreiben, das war ja das erste Problem,
was wir hatten und auch durch den Acception-Fluss kann es nicht passieren,
dass diese Zeile übersprungen wird.
Wenn ihr das Thema irgendwie spannend findet, dann sucht doch
mal nach Triy with Resources oder es heißt auch Arm Block.
Da müsst ihr wahrscheinlich noch Java davor schreiben, sonst findet ihr was ganz komisches.
Okay. Ja, das ist also wirklich toll.
Man muss sich um das Schließen der Dateien nicht mehr selber kümmern,
das passiert einfach alles auf magische Art und Weise im Hintergrund.
Gefällt mir ganz gut. Okay, ja, gibt es dazu noch Fragen?
Also was eben wichtig ist, ist zu verstehen,
wir haben hier Code, der potenziell eine IO-Workception schmeißen will.
Wir deklarieren hier in unserer Signatur, wir kümmern uns nicht selber
um die IO-Workception, sondern unser Aufrufer muss das tun.
Und der Aufruf war tut es tatsächlich, hier ruft er
uns ja auf und hier kümmert er sich um den Fehlerfall,
der eintreten kann.
So, auf dem Niveau wird auch der Code sein,
die in der Übung schreiben werdet.
Ihr habt also irgendwo in einem Modul ganz weit unten einen Fehler,
der soll hochgeleitet werden und weiter oben soll er dann
erst behandelt werden
Darfst du noch fragen? Ja. Sorry, ich habe
die Frage akustisch nicht verstanden. Das Finally. Ja,
das Problem ist, also rein syntaktisch und so ist das alles kein Problem.
Du kannst hier ein Finally hinschreiben. Aber wir haben hier
ja nicht diesen Output-Stream, den wir schließen müssen.
Der ist ja in der Methode unten gewesen. Ja,
aber du kannst in das Finaly hier auch, ja,
also man kann auch ein Try, ein Catch und ein Finaly schreiben.
Ja, das geht. Okay. Gut,
jetzt haben wir
noch drei Minuten
Oder acht, die Umweltpause geht ja mal fünf Minuten.
Was wollen wir denn als nächstes machen? File Coppy. Ja,
bei dem File-Coppy wollte ich euch eigentlich dieses Tride zeigen,
das habe ich euch jetzt ja schon gezeigt.
Vielleicht machen wir es trotzdem. Dann haben wir mal so
einen schönen Kontrast, dass es hoffentlich kürzer ist als in Java.
Okay, ich mache, ich mache mal hier ein neues Projekt.
Nennen wir das mal File Coppy. So,
dann tue ich da mal, das kann ich mal schließen.
Ich dürfte da mal eine neue Klasse rein,
keine Ahnung,
ein Coppy
So, und dann machen wir da jetzt mal so eine statische Methode rein.
Ich bin mal echt gespannt, aber ich glaube,
in zwei Minuten kriegen wir es nicht mehr hin, oder?
Mal gucken, mal gucken, wie weit wir kommen.
Also Sourcename und Death Name, so hieß es ja auch in
C. Okay, und jetzt will ich die quasi öffnen.
Also, wie hieß das eben, File Output Stream?
Genau, dann brauche ich jetzt also einen File Input Stream. File Sourcename,
das muss inportiert werden, dann werde ich eine Variable zuweisen,
das nennen wir einfach mal in,
dann kann das eine Acception werfen,
dann sage ich mal,
nee,
was will er von mir
So. Dann sag ich mal, File Outdoor Stream.
Das war auch wieder eine Variable rein.
Also ich muss es importieren. Dann in eine Variable.
Die nennen wir mal Out. Okay. Dann brauchen wir
wieder diesen Buffer. Ah nee, sorry. Nee,
richtig. Chan-Buffer, nee, bye. Jopas fahren,
nehmen wir mal wieder irgendwie 1000 oder so.
Okay, und jetzt muss ich ja Naybyte,
muss da stehen
Nicht, dass ich noch das Programmierikt hatte, achso.
Gut, jetzt muss ich irgendwie lesen aus dem Inputstream.
Da gibt es zum Glück eine Methode, Reed.
Da kann ich ja sagen,
lies doch mal bitte in den Buffer rein und ich kriege zurück,
wie viele Bytes gelesen wurden.
Ja, ich will, dass da tausend Bytes liest,
aber es könnte ja sein, dass weniger zurückkommen.
Was will er jetzt von mir? Achso, iO Acception
. Das Problem erinnert ihr euch noch. Ich verallgemeinere das
jetzt einfach mal auf iO Acception.
Also das muss ich importieren.
Okay, gut
Und jetzt kann ich einfach mal sagen, vielleicht,
solange ich mehr als null Bytes gelesen habe,
so ähnlich hatte ich das ja auch ein Ziel gemacht.
Das sieht jetzt vielleicht ein bisschen komisch aus, so ein kleines Idiom.
Ich habe also hier eine Zuweisung stehen und das Ergebnis dieser Zuweisung
vergleiche ich jetzt, ob das größer ist als null.
Und wenn das der Fall ist, dann kann ich das wieder schreiben, Buffer.
So. Muss ich sonst noch was tun? Warum ist hier
ein gelbes Ding an? Is not used. Ach so,
ich darf ja nicht den ganzen Buffer schreiben,
sondern nur die N-Bytes. Es könnte ja sein,
dass er weniger eingelesen hat,
muss ich
das hier nehmen
Okay. Macht das Sinn? Warum gibt es jetzt hier
noch irgendwie, was wir da hier...
Ach, guck mal, ich habe schon wieder vergessen,
sie zu schließen. Das vergesse ich irgendwie jedes Mal.
Dann kann ich doch einfach mal das hier wieder nehmen.
Das hier in Runde klammern. Kann man da auch mehrere
hintereinander schreiben? Glaubt ihr, das geht? Das habe ich
ehrlich gesagt noch nie ausprobiert. Wir gucken, wir mit
einem Semikolam. Okay, machen wir einmal Formatierung.
Guck mal, scheint sich nicht zu beschweren.
Okay. Okay, dann mache ich jetzt mal nichts Grafisches.
Das sieht doch alles ganz gut aus.
Okay, ich glaube, mehr müssen wir nicht machen
Wisst ihr was, das probieren wir jetzt einfach mal.
Wir brauchen noch eine Main-Methode. Wir haben noch ein paar Minuten,
das ist kein Problem, das kriegen wir noch hin.
Also wir rufen jetzt diese Copy-Methode auf und dann übergeben wir mal Arcs 0
als den Source Name und Arcs 1 als den Dest Name.
Das müsste es doch eigentlich sein, oder? Wir können
hier nochmal auf die Konsole schreiben, was wir da gerade versuchen.
Copy from Source Name to Test Name.
Okay, das probiere ich jetzt einfach mal aus.
Gehen wir doch mal in den Workspace.
Was haben wir denn da? Wir haben das genannt.
So. Okay, jetzt habe ich das in dem Paket drin liegen.
Ich glaube, ich muss jetzt... Copy und Glashockey.
Ich glaube, ich muss jetzt sagen, Java-File-Copy.copy.
Und jetzt muss ich die Datei angeben, aus der ich lesen will.
Also ich will lesen aus Hormfred-Fox.txt. Und ich will schreiben,
in test.takes, die direkt in dieses Verzeihnis sein.
Hey, es hat funktioniert. Okay, dann würde ich sagen,
mit diesem Erfolgserlebnis entlasse ich euch bis nächste Woche.