12. Abstrakte Klassen, Exceptions, Abschluss

Werbung
12. „Advanced Features“, Abschluss
•
Abstrakte Klassen
•
Ausnahmen
•
Rückblick und Ausblick
László Böszörményi
ESOP
Abschluss - 1
12. 1. Abstrakte Klassen
•
Am oberen Ende einer Hierarchie finden wir oft eine
reine Abstraktion
–
•
•
Möbel, Fahrzeug, Vogel, Tier etc.
Java bietet dafür abstrakte Klassen an
–
Diese enthalten zumindest eine abstrakte Methode
–
Abstrakte Methoden haben nur Methodenkopf (keinen Rumpf)
–
Sie werden erst später (in einer Subklasse) implementiert
(durch Überschreiben)
–
Abstrakte Klassen können nicht angelegt werden
Interfaces sind spezielle abstrakte Klassen
–
Alle Methoden sind abstrakt
–
Es gibt keine Variablendeklarationen
László Böszörményi
ESOP
Abschluss - 2
Fahrzeug- Modell
Abstrakte Superklasse
Jedes Fahrzeug hat:
Bewegung, Größe, Preis ...
Fahrzeug
PKW
LKW
Cabrio
Schlepper
Fahrzeuge an sich gibt es
nicht: Die Extension der
abstrakten Klasse ist leer
Subklasse von
Fahrzeug und
Superklasse von
Schlepper
Fahrzeug
Cabrio
LKW
PKW
Schlepper
Ein PKW hat
Kofferraum, Kindersitz ...
László Böszörményi
ESOP
Abschluss - 3
Abstrakte Basisklasse mit Ordnung
•
Wir definieren eine generische Liste, die beliebige
Objekte speichern kann, die von einer Basisklasse
abgeleitet werden
•
Eine abstrakte Klasse (nennen wir sie BasicObject)
•
Alternativlösung wäre: Elemente sind Objects, die ein
gemeinsames Interface implementieren
•
Elemente an der Liste sind Subklassen von BasicObject
•
Vorteil
•
–
Kann default-Implementierungen anbieten
–
Alle Eigenschaften werden vererbt
Nachteil: Mehrfachvererbung nicht möglich
László Böszörményi
ESOP
Abschluss - 4
Klasse BasicObject
public abstract class BasicObject { // BasicObject mit unique ID und Vergleich
abstract int compareWith (BasicObject x); // Rückgabewert:
/* < 0, wenn this ist kleiner als x
> 0, wenn this ist größer als x
= 0, wenn this und x gleich sind */
private static long ident = 0;
// Statischer Zähler: für den eindeutigen ID
private long id;
// Identifier des aktuellen Objektes
BasicObject() { ident ++; id = ident; };
// Jedes Objekt erhält eigenen ID
public String toString () {return ("[" + id + "]"); }
// BasicObject-s werden mit vorangestellten: [id] ausgeschrieben
} // BasicObject
László Böszörményi
ESOP
Abschluss - 5
Node und List mit BasicObject Info-Teil
public class Node {
// 03.11.2000. LB
BasicObject info;
// info ist nun ein Objekt, das
Node
// die Klasse BasicObject erweitert
next;
public Node (BasicObject info, Node next) // Konstruktor
{ this.info = info; this.next = next;}
} // Node
public interface List {
// 03.11.2000. LB
public boolean search (BasicObject key);
// Die Schlüsselwerte sind
public void insert(BasicObject key);
// Subklassen von BasicObject
public boolean remove (BasicObject key);
public String toString ();
} // List
László Böszörményi
ESOP
Abschluss - 6
CompInt als Subklasse von BasicObject
public class CompInt extends BasicObject {
// 20.11.2000. LB
private int i;
// Wert des CompInt-Objektes
public CompInt(int num) {i = num; }
// Konstruktor
public String toString () {
// Überschreibt und benutzt
return super.toString() + i;
// die Methode der Superklasse:
} // toString
// toString von BasicObj
public int compareWith (BasicObject x) {
if
(i < ( (CompInt) x).i) return -1;
else if
(i > ( (CompInt) x).i) return 1;
else
// Implementiert die abstrakte
// Methode der Superklasse
return 0;
} // compareWith
} // CompInt
László Böszörményi
ESOP
Abschluss - 7
Person als Subklasse von BasicObject
public class Person extends BasicObject { // 20.11.2000. LB
private String name;
// Name der Person
public Person (String person_name) { // Konstruktor
name = person_name;
} // Person
public String toString () {
return super.toString() + name;
// Überschreibt und benutzt toString
// der Superklasse BasicObject
} // toString
public int compareWith (BasicObject p2) {
// Implementiert die
return this.name.compareTo( ( (Person) p2).name ); // abstrakte Methode
} // compareWith
// Benutzt die compareTo-Methode der String-Klasse
} // Person
László Böszörményi
ESOP
Abschluss - 8
Benutzung bleibt gleich
static void useList(List list) {
String [] persons1 = {"Pete", "May", "Paul", "Bob"};
String [] persons2 = {"Sue", "Mic", "Xe", "Xa", "Ada", "Xu"};
for (int i = persons1.length - 1; i >= 0; i -- ) list.insert ( new Person (persons1[i]) );
Out.println(list);
for (int i = 0; i < persons2.length; i++ ) list.insert( new Person (persons2[i]) );
Out.println(list);
for (int i =0; i < persons2.length; i+= 3 ) {
Person p = new Person (persons2[i]); String s;
if ( list.remove (p) ) s = " entfernt"; else s = " nicht enthalten";
Out.println(p + s);
} // for i
( [1]Bob [3]May [2]Paul [4]Pete )
Out.println(list); ( [9]Ada [1]Bob [3]May [6]Mic [2]Paul [4]Pete [5]Sue [8]Xa [7]Xe [10]Xu )
[11]Sue entfernt
} // useList
[12]Xa entfernt
( [9]Ada [1]Bob [3]May [6]Mic [2]Paul [4]Pete [7]Xe [10]Xu )
László Böszörményi
ESOP
Abschluss - 9
Implementierung der generischen Liste (1)
public class NonRekList implements List {
// 03.11.2000. LB
private Node head = null;
public boolean search (BasicObject key) {
Node actual = head;
while ( actual != null && key.compareWith(actual.info) != 0 ) actual = actual.next;
return actual != null;
} // search
public String toString () {
Node actual = head;
String listString = "";
while (actual != null ) {
listString += actual.info + " "; actual = actual.next;
} // while
return "( " + listString + ")";
} // toString
László Böszörményi
ESOP
Abschluss - 10
Implementierung der generischen Liste (2)
public void insert (BasicObject key) {
if ( (head == null) || ( key.compareWith(head.info) < 0 ) )
head = new Node(key, head);
else {
Node previous = head,
actual = head.next;
while (actual != null && key.compareWith(actual.info) > 0) {
previous = actual;
actual = actual.next;
} // while
previous.next = new Node(key, actual);
} // if
} // insert
László Böszörményi
ESOP
Abschluss - 11
Implementierung der generischen Liste (3)
public boolean remove (BasicObject key) {
if (head == null) return false;
else if ( key.compareWith(head.info) == 0 ) {
head = head.next;
return true;
} // if (head.info == key)
else {
Node previous = head, actual = head.next;
while (actual != null && key.compareWith (actual.info) != 0 ) {
previous = actual; actual = actual.next;
} // while
if (actual != null) previous.next = actual.next;
return actual != null;
} // if (head == null)
} // remove
} // NonRekList
László Böszörményi
ESOP
Abschluss - 12
12. 2. Ausnahmen
•
Reaktionen auf fehlerhafte Ereignisse sollten als Ausnahmen
(exceptions) behandelt werden
– Damit wir der „normale“ Teil einfacher
– Die Versuchung ist kleiner, Fehler unbehandelt zu lassen
•
Behandlung der Fehler kann nicht immer dort erfolgen, wo
der Fehler aufgetreten ist: sie muss dann delegiert werden.
•
Beispiele
– Falsche Eingabe von der Tastatur: Benutzer wiederholen lassen
– Falsches Dateiformat
•
Benutzer anfordern, einen anderen Dateinamen anzugeben
•
Aufrufer kann vielleicht ohne diese Daten weiterrechnen: delegieren
– Falscher Index bei einem Array, null-Wert bei einer Objektvariable:
•
Vielleicht kann der Aufrufer die Situation noch „retten“ – oder Abbruch
László Böszörményi
ESOP
Abschluss - 13
Exceptions in Java
•
Eine Ausnahme (exception) ist ein spezielles Objekt
•
Eine Ausnahme kann
– Erzeugt („geworfen“ – throw),
– Behandelt („aufgefangen“ – catch) und
– „Angekündigt“ werden (throws im Kopf einer Methode)
•
Eine Ausnahme unterbricht die Ausführung der
Anweisungen
•
Ein Handler wird gesucht, die die Ausnahme
bearbeitet
•
Nach der Bearbeitung läuft das Programm weiter
László Böszörményi
ESOP
Abschluss - 14
Die try-Anweisung
try
{
Folge der „normalen“ Anweisungen – die den fehlerfreien Fall bearbeiten
} // try
catch (Exception1 e1)
{ // Die catch-Zweige werden der Reihe nach durchgesucht
Behandlung der Ausnahmen der Klasse Exception1 (und seiner Subklassen)
} // catch Exception1
catch (Exception2 e2)
{
Behandlung der Ausnahmen der Klasse Exception2 (und seiner Subklassen)
} // catch Exception2
finally
{
Diese Anweisungen werden auf jeden Fall ausgeführt,
unabhängig davon, ob der try-Zweig normal abgelaufen ist,
oder unterbrochen wurde (durch Ausnahme, oder break oder return).
} // finally
László Böszörményi
ESOP
Abschluss - 15
Ausführung der try-Anweisung
1. Die Anweisungsfolge des try-Blocks wird ausgeführt
2. Tritt eine Ausnahme E auf, dann wird ein Handler
gesucht, und sein Block ausgeführt
1. Der erste catch-Block (von oben nach unten) mit einer
Ausnahmeklasse A, die eine Superklasse von E ist (E ⊂ A)
•
Das Ausnahmeobjekt wird der Variable im catch-Klausel zugewiesen
2. Falls kein entsprechender catch-Block gefunden
1. Suche in den äußeren Blöcken, von innen nach außen
2. Suche entlang der Aufrufskette aufwärts
•
Wenn bis in die main Methode kein Handler gefunden: Abbruch, Fehler
3. Wenn ein finally-Block definiert ist, wird er auf jeden Fall
ausgeführt
4. Nach der Fehlerbehandlung läuft das Programm nach
der try-Anweisung weiter
László Böszörményi
ESOP
Abschluss - 16
Hierarchie von Exceptions-Klassen
•
Oberste Exception-Klasse: java.lang.Throwable
– Methode zur Fehlermeldung (geerbt durch alle):
String Throwable.getMessage()
– Weitere Felder und Methoden können definiert werden
•
Vordefinierte Unterklassen:
– java.lang.Error
•
Für Fehler, die meistens nicht reparierbar sind: Fehlermeldung
– java.lang.Exception
•
Für Fehler, die sinnvoll behandelt werden können, z.B:
•
java.io.InterruptedIOException – mit der zusätzlichen Methode:
–
László Böszörményi
public int bytesTransferred(): Anzahl der übertragenen Bytes
ESOP
Abschluss - 17
Muster der korrekten Dateibehandlung
try
{
// Der „normale“ Teil des Programms:
readFromFile("File_Name“);
...
// Datei wird gesucht, eröffnet und bearbeitet
} // try
catch (FileNotFoundException e)
{
Behandlung des Falls, die Datei wurde nicht gefunden
} // catch FileNotFoundException
catch (IOException e)
Fehlerbehandlung
{
Behandlung des Falls, die Datei enthält fehlerhafte Daten
} // catch IOException
catch (MyException e)
{
Behandlung von benutzerdefinierten Fehlern
} // catch MyException
finally
file.close();
{
// Datei wird auf jeden Fall geschlossen
} // finally
László Böszörményi
ESOP
Abschluss - 18
Behandlung falscher Eingabe
static int GetInt()
throws NumberFormatException { // Leitet die Ausnahme nur weiter
String s = "";
try {s = new BufferedReader (new InputStreamReader (System.in)).readLine(); }
catch (IOException e) {Out.println("Grober Fehler in der Eingabe");}
return Integer.parseInt (s);
// Erzeugt die Ausnahme NumberFormatException
} // GetInt
static void main(String [] args) {
int result, dividend, divisor;
xxx
Fehler: keine Zahl
12
qqq
Fehler: keine Zahl
try {
dividend = GetInt(); divisor = GetInt(); result = 0;
while (dividend >= divisor) { result++; dividend -= divisor; }
Ergebnis, falls
Eingabe korrekt
Out.println("Ganzzahliger Quotient = " + result);
}
catch (NumberFormatException e) {Out.println("Fehler: keine Zahl");}
} // main
László Böszörményi
ESOP
Abschluss - 19
Benutzerdefinierte Ausnahme
class MyException extends Exception {
// Eigene Ausnahme-Klasse
String text;
// Beschreibung der Ausnahme
MyException (String t) { text = t;}
// Konstruktor
public String getMessage() { return text; } // Überschreibt getMessage
} // MyException
...
static int GetPosInt () throws NumberFormatException, MyException { // Ankündigung
String s = "";
try {s = new BufferedReader (new InputStreamReader (System.in)).readLine(); }
catch (IOException e) {Out.println("Grober Fehler in der Eingabe");}
int i = Integer.parseInt (s);
// Ausnahme die hier auftritt, wird weitergeleitet
if (i <= 0) throw new MyException ("Eingabe nicht positiv"); // Erzeugt Ausnahme
return i;
} // GetPosInt
László Böszörményi
ESOP
Abschluss - 20
Zyklische Behandlung von Ausnahmen
static void main(String [] args) {
while (true) {
// Die Schleife wird durch break explizit untebrochen
try { Out.println("Dividend und Divisor:");
int dividend = GetPosInt(), divisor = GetPosInt(), result = 0;
while (dividend >= divisor) { result++; dividend -= divisor; }
Out.println("Ganzzahliger Quotient = " + result);
break; // Normale Ausführung endet
Dividend und Divisor:
12
-3
MyException: Eingabe nicht positiv
Dividend und Divisor:
qqq
java.lang.NumberFormatException: keine Zahl
Dividend und Divisor:
12
3
Ganzzahliger Quotient = 4
} // try
catch (NumberFormatException e)
{Out.println(e + " keine Zahl");}
catch (MyException e)
{Out.println(e);}
} // while
} // main
László Böszörményi
Gibt den Namen der
Exception auch aus
ESOP
Abschluss - 21
Schachtelung von try und catch Blöcken
try {
try {
Fehler: java.lang.ArithmeticException: / by zero
Fehler2: java.lang.ArithmeticException: / by zero
int i = 5 / 0;
} // try
catch (ArithmeticException e) {
Out.println("Fehler: " + e );
// Default-Text vom ArithmeticException
int j = 5 / 0; // Ausnahme in Ausnahme: Wird im einschließenden Block
} // catch e
// behandelt: führt zu keiner unendlichen Ausnahmebehandlung
} // try
catch (ArithmeticException e2) {
Out.println("Fehler2: " + e2 ); // Default-Text vom ArithmeticException
} // catch e2
László Böszörményi
ESOP
Abschluss - 22
Compilationsunsicherheit durch try
•
Die Anweisungsfolge in try kann an beliebiger Stelle
unterbrochen werden
•
Der Compiler kann nicht wissen, wann das geschieht
void myMethod()
{
int x, y, z = GetInt();
try {
// Könnte 0 eingelesen werden
y = 1;
x = 5;
y = x / z;
// Verursacht ArithmeticException, falls z == 0
} // try
catch (ArithmeticException e) { Out.println("Fehler: " + e );}
int i = x; // Fehler bei der Compilation: variable x might not have been initialized
} // myMethod
László Böszörményi
ESOP
Abschluss - 23
12. 4. Rückblick und Ausblick
•
Grundkonzepte der strukturierten und
objektorientierten Programmierung und ihre
Abbildung auf Java erarbeitet
•
Die Entwicklung von Softwaresystemen benötigt
noch viel mehr (siehe Lehrveranstaltungen später)
•
Wir finden meistens eine große Anzahl von
vorgefertigten Klassen, die ein Framework bilden
•
Die Benutzung von Frameworks macht die
Programmierung viel effizienter – der Aufwand fürs
Erlernen der Frameworks kann aber beachtlich sein
László Böszörményi
ESOP
Abschluss - 24
Herunterladen