Folienskript

Werbung
494
Die Verwaltung wird um eine Objektvariable semester erweitert in der das aktuell
betrachtete Semester drinsteht.
495
Der genau Prozess des Ladens und Speichern wird später genauer analysiert.
Hier soll zunächst das Prinzip mit einer Realisierungsmöglichkeit erklärt werden.
Parallel dazu wird der Umgang mit Exceptions beschrieben.
Hinweis: Es werden hier 8-Bit-Versionen der Streams betrachtet (gibt ähnliche
Klassen für Uni-Code, 16 Bit).
496
Das Schließen von Dateien ist ein sehr zentraler Schritt, da ein Vergessen dieser
Aktion oftmals nicht direkt zu einem Fehler führt. Man spricht von einem
schleichenden Fehler, der oft erst später gespürt wird, wenn eine Applikation
deutlich langsamer läuft oder sich das Betriebssystem plötzlich weigert, eine
bestimmte Aktionen, die sonst immer möglich sind, auszuführen.
497
Der Dateiname ist beliebig, die Endung aber sinnvoll, da eine syntaktische
korrekte XML-Datei erzeugt wird. Die genaue Kenntnis von XML ist hier nicht
notwendig, aber leicht erlernbar und sollte irgendwann im Studium genauer
verstanden werden.
498
499
500
Die Idee der mehrfach geschachtelten Konstruktoren wird später erklärt, wichtig
ist hier nur, dass ein Stream zu einer Datei geöffnet wird und so Informationen in
die Datei geschrieben werden.
501
Anmerkung: Das Exception Handling wurde in Java 7 etwas vereinfacht. Da es
hier um die Grundlagen geht, die in der präsentierten Form in anderen
Programmiersprachen sehr ähnlich sind, wird die klassische Variante vorgestellt.
Diese Variante ist natürlich auch in Java 7 nutzbar.
502
503
504
Die Zeilen "normalesProgramm" stehen für einfache Programmzeilen, die keine
try-catch-Blöcke enthalten.
Es sind beliebig viele catch-Blöcke möglich.
Der finally-Block kann weggelassen werden, wenn er existiert, wird er immer
garantiert ausgeführt.
Der angedeutete Fall2 wird später behandelt, falls es keinen finally-Block gibt,
wird die Exception direkt an die aufrufende Methode weitergegeben.
505
Durch die verwendete Klasse XMLEncoder werden alle mit writeObject(.)
geschriebenen Objekte im XML-Format abgespeichert. Dies ist möglich, da die
Bean-Eigenschaften genutzt werden, bei denen durch get- und set- ein einfaches
Lesen und Schreiben möglich ist.
XML ist eine sogenannte Auszeichnungssprache mit einfachen syntaktischen
Regeln. Basierend auf diesen Regeln kann man eine Teilmenge von XMLDokumenten definieren, die zur Verwaltung bestimmter Daten genutzt werden
können. XML ist dabei recht einfach maschinenlesbar, jede ordentliche
Programmiersprache bietet Bibliotheken zur XML-Bearbeitung, und kann auch
von Menschen gelesen und notfalls geschrieben werden, was häufig in
Konfigurationsdateien genutzt wird.
Das Thema XML wird in späteren Vorlesungen des Studiums vertieft.
506
Der Hintergrund des Problems ist es, dass BlueJ selbst als Java-Programm die
Ausführung der Java-Programme steuert. Bei dieser Steuerung ist leider nicht
sichergestellt, dass alle benutzten Klassen auch zur Nutzung mit XMLDecoder
zur Verfügung stehen. Dies ist eine der wenigen Programmzeilen, die man nur
hinschreiben, aber noch nicht verstehen muss.
Wird das Java-Programm außerhalb von BlueJ genutzt, ist die Ergänzung
überflüssig, schadet aber bei den vorgestellten Programmen auch nicht.
507
508
Man kann auch vollständig auf die Klasse File hier verzichten. Sie ermöglicht
aber eine genauere Analyse des Fehlerfalls und kann deshalb hilfreich sein.
509
510
511
Die Warnung bezieht sich nur auf das Casten der Liste, da der genaue Typ der
Liste, d. h. welche Objekte in ihr gespeichert sind, nicht explizit mit abgespeichert
wird. (Längere Geschichte, da erst mit Java 5 die Möglichkeit entstand, den
Typen der Listenelemente anzugeben)
512
513
514
Man beachte, dass bei diesem Beispiel die zu file gehörige Datei eventuell offen
bleiben kann, da z. B. bei einer Exception in file.readObject() die Zeile file.close()
nicht ausgeführt wird. Dieses Problem wird wenige Folien später gelöst.
515
516
Dies ist die Variante, die immer genutzt werden soll, wenn mit kritischen
Ressourcen wie Dateien gearbeitet wird. Die Variable wird vor dem try deklariert,
im try-Block genutzt und im finally-Block garantiert geschlossen.
517
Der Testfall zeigt, dass die Ausgangssituation mit zwei IMI- und MID-Studenten
abgespeichert wird, danach zwei Studiengänge gelöscht und dann die
gespeicherten Daten wieder eingelesen werden.
Da keine Exception erwartet wird, steht im catch-Block ein "assertTrue(false)",
was dazu führt, dass, wenn diese Anweisung erreicht wird, immer ein Fehler
erzeugt wird.
Generell gilt bei JUnit, dass nicht behandelte Exceptions wie Fehler behandelt
werden und so zu einem erfolglosen Testfall führen.
518
Wieder wurde die Programmstelle, von der man erwartet, dass sie nicht erreicht
wird, mit assertTrue(false) gekennzeichnet. Alternativ könnte hier auch fail()
stehen, was auch nur bedeutet, dass die eigentlich nicht zu erreichende
Programmzeile doch erreicht wurde.
519
Die Zeilen "normalesProgramm" stehen für einfache Programmzeilen, die keine
try-catch-Blöcke enthalten.
Tritt in machWas eine Exception vom Typ ExTyp2 auf, wird diese an die
aufrufende Methode weitergeleitet. Da die Exception hier nicht gefangen wird,
muss sie in der throws-Deklaration von rufAuf stehen.
520
521
522
523
Natürlich kann man auch andere Konstruktoren nutzen, Objektvariablen
definieren und Methoden ergänzen. Dies kann z. B. Sinn machen, wenn man die
Fehlerbehandlung weiter konkretisieren möchte.
524
525
526
Das Bild zeigt nur einen recht kleinen Ausschnitt aller bereits existierenden
Klassen zur Fehlerbehandlung.
Es fällt auf, dass es die noch allgemeinere Klasse Throwable als Grundlage gibt,
wobei es üblich ist, eigene Exceptions von der Klasse Exception erben zu lassen
und gegebenenfalls einen eigenen Exception-Vererbungsbaum aufzubauen.
Alle von Error erbenden Klassen stehen für gravierende Fehler, die man in der
eigenen Software nicht behandeln sollte, und teilweise gar nicht behandeln kann.
Da jede Programmausführung Speicher benötigt, ist es unklar, ob auf
"OutOfMemory" reagiert werden kann.
Auch die von RuntimeException erbenden Klassen stehen meist für größere
Fehler, können aber gegebenenfalls wie eine IllegalArgumentException
abgefangen werden. Für die bisher genannten Klassen gilt, dass sie nicht in einer
throws-Liste stehen müssen, da in Java keine Behandlung des Fehlers erwartet
wird. Die Klassen können aber trotzdem in throws-Listen stehen und mit catchBlöcken bearbeitet werden.
Die "normalen" Exceptions müssen immer mit try-catch-Blöcken behandelt
werden.
527
528
529
530
531
532
533
534
Bei den Klassenvariablen darf kein "this" genutzt werden, da diese Variablen
nicht zu this, also dem jeweiligen Objekt, gehören. Man erkennt daran auch, dass
die nur bei Namensgleichheit notwendige Markierung von Objektvariablen mit
"this." das Lesen von Programmen bei konsequenter Nutzung von this eindeutig
erleichtern kann. Sieht man jetzt eine Variable ohne this, muss man nur prüfen,
ob es sich um eine lokale Variable oder einen Parameter handelt und, wenn
nicht, muss es eine Klassenvariable sein, insofern die Coding-Guidelines
eingehalten wurden. Der Klassenname vor einer Klassenvariablen kann
weggelassen werden, erhöht aber die Lesbarkeit.
535
Beim Zugriff von außen muss der Klassenname vor der Klassenmethode stehen.
536
537
538
539
540
Man erkennt, dass Klassenvariablen vererbt werden, genauer auch Eigenschaft
der erbenden Klasse, also nicht der Objekte werden.
Man kann nur Objekt-Methoden überschreiben, da nur hierfür dynamische
Polymorphie sinnvoll einsetzbar ist. Man kann allerdings Klassenmethoden mit
der gleichen Signatur anlegen,
die dann zur jeweiligen Klasse gehören und auch in denen aufgerufen werden
können.
Das Beispiel zeigt die Möglichkeit Klassenvariablen ohne die Klasse davor zu
nutzen, was die Lesbarkeit deutlich verringert.
Leider ist es in Java sogar möglich, klav als Klassenvariable von K2
anzusprechen, was nach obiger Vererbungsregel natürlich formal korrekt ist, aber
in einer praktischen Nutzung zu absolut unlesbaren Programmen führen würde.
541
542
System.out.println() ist also aus objektorientierter Sicht ein extrem merkwürdiger
Befehl, weshalb er bisher in "ordentlichen" Objekten der Klasse EinUndAusgabe
gekapselt wurde. Bei System.out handelt es sich bei out um eine nach außen
sichbare (public) Klassenvariable der Klasse System. In out selbst steht ein ganz
"normales" Objekt, das eine Methode println() anbietet. Der Methode println(.)
können beliebige Objekte übergeben werden, für die dann die toString()-Methode
aufgerufen wird. Das "ln" am Ende deutet ein "Linefeed" an und führt dazu, dass
ein Zeilenumbruch nach der Ausgabe durchgeführt wird. Es gibt die ähnliche
Methode print, die die gleiche Ausgabe macht, aber am Ende auf einen
Zeilenumbruch verzichtet.
543
Ein typisches Beispiel bei dem Objektmethoden keinen Sinn machen, ist die
Klasse EinUndAusgabe. Hier wird ausschließlich ein Objekt erstellt, damit man
die Methoden ausführen kann. Es gibt keine echten Objektvariablen, die sich
irgendeine Zustandsinformation merken.
544
Vereinfachend kann man sich an dieser Stelle noch double durch Double und
long durch Log ersetzt vorstellen. Die Klasse Long kann auch ganze Zahlen
aufnehmen, kann aber wesentlich größere Zahlen als Integer darstellen, braucht
dafür aber mehr Speicherplatz.
545
546
547
548
549
550
551
Die Konstanten wurden durch Aufrufe von Klassenmethoden ersetzt.
552
553
554
555
556
557
Herunterladen