Programmbausteine & Komponenten 5.4 Objektorientierte Bausteine und Bibliotheken Wir verwenden die Begriffe „Programmbaustein“ und „Programmkomponente“ hier synonym. Idee: Dieser Abschnitt führt in den Komponenten-/ Bausteinbegriff und in die Java-Bibliothek ein. Ziel ist die Vertiefung der in 5.3 erläuterten Konzepte und deren Anwendung. Konstruiere Softwaresysteme aus vorgefertigten Bausteinen durch • Anpassen der Bausteine: Überblick: - Instanzieren von Parametern - Spezialisierung • Bausteine, Schnittstellen und Bibliotheken • Verbinden der Bausteine/Komposition: • Klassen zur Ausnahmebehandlung - Verbindungsmechanismen der Komponenten • Ströme zur Ein- und Ausgabe - zusätzlicher Programmcode (engl. glue code) 5.4.1 Bausteine, Schnittstellen und Bibliotheken Wichtige Fragestellungen: • Klärung und Diskussion der Begriffe - Sind die Bausteine direkt einsetzbar oder müssen sie noch vervollständigt werden? - Wie anpassbar, wie allgemein sind die Bausteine? - Programmbaustein, -komponente - Sind die Bausteine unabhängig voneinander, hierarchisch strukturiert, wechselseitig abhängig? - API, Programmierschnittstelle - Bibliothek - Wie werden sie zusammengesetzt? • Überblick über die Java-Bibliothek 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern - Wie kann man sie auffinden? 672 Vereinfachend gehen wir davon aus, dass ein Baustein durch eine oder mehrere Typdeklarationen realisiert ist. Die Schnittstelle eines Bausteins entspricht der öffentlichen Schnittstelle dieser Typen. 05.02.2007 public final class Boolean implements java.io.Serializable { public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); public static final Class TYPE = ...; - unabhängige Bausteine - eigenständige Bausteine - kooperierende Bausteine public Boolean(boolean value) { this.value = value; } public Boolean(String s) { this( toBoolean(s) ); } public boolean booleanValue(){ return value; } public static Boolean valueOf(String s){...} public String toString() { ... } public int hashCode() { ... } public boolean equals(Object obj) { if (obj instanceof Boolean) { return value == ((Boolean)obj).booleanValue(); } return false; } public static boolean getBoolean(String n){..} Wir erläutern diese Aufteilung jeweils durch Begriffsklärung und Beispiele in Java. Begriffsklärung: (unabhängige Bausteine) Wir nennen Bausteine oder Programmkomponenten unabhängig, wenn sie ohne Kenntnis und Existenz anderer Bausteine bzw. Komponenten angewandt werden können. In der Schnittstelle unabhängiger Bausteine kommen im Wesentlichen nur vordefinierte und Standardtypen vor. Typische Beispiele sind einfache Behälterbausteine (z.B. SLinkedList), die Klasse String oder die Wrapper-Klassen, aber auch vollständige Anwendungsprogramme. © A. Poetzsch-Heffter, Universität Kaiserslautern 673 Beispiel: (unabhängiger „Baustein“) Wir betrachten drei Arten von Bausteinen: 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern } 674 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 675 Beispiel: (eigenstängiger Baustein) Unabhängigkeit erleichtert das Verständnis von Bausteinen. Trotzdem sind unabhängige Bausteine in Programmbibliotheken eher selten. Listen mit Iteratoren bilden einen Baustein. Als Beispiel betrachten wir die Typen LinkedList, Iterator und ListIterator aus dem Paket java.util. Häufig sind unterschiedliche, aber ähnliche Bausteine Teil einer Klassen- bzw. Typhierarchie. Dadurch sind speziellere Bausteine oft von allgemeineren abhängig. public interface Iterator { boolean hasNext(); Object next(); void remove(); } Begriffsklärung: (eigenständige Bausteine) Wir nennen Bausteine oder Programmkomponenten eigenständig, wenn die Kenntnis und Existenz ihrer Supertypen für ihr Verständnis und ihre Anwendung ausreicht und sie eingesetzt werden können, ohne mit anderen Bausteinen kooperieren zu müssen. In der Schnittstelle eigenständiger Bausteine kommen im Wesentlichen nur vordefinierte Typen, Standardtypen und Supertypen der Klassen vor, die den Baustein implementieren. Typische Beispiele sind komplexere Behälterbausteine und Stromklassen. 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 676 public class LinkedList extends AbstractSequentialList implements List, Cloneable, Serializable { public LinkedList() public LinkedList(Collection c) public Object getFirst() public Object getLast() public Object removeFirst() public Object removeLast() public void addFirst(Object o) public void addLast(Object o) public boolean contains(Object o) public int size() public boolean add(Object o) public boolean remove(Object o) public boolean addAll(Collection c) public boolean addAll(int ix, Collection c) public void clear() public Object get(int index) public Object set(int ix, Object elem) public void add(int index, Object elem) public Object remove(int index) public int indexOf(Object o) public int lastIndexOf(Object o) // ... weiter nächste Seite 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 678 public interface ListIterator extends Iterator { boolean hasNext(); Object next(); boolean hasPrevious(); Object previous(); int nextIndex(); int previousIndex(); void remove(); void set(Object o); void add(Object o); } 05.02.2007 // ... public public public public public public public public public ... // © A. Poetzsch-Heffter, Universität Kaiserslautern 677 ListIterator listIterator() ListIterator listIterator(int ix) Iterator iterator() List subList(int from, int to) boolean equals(Object o) int hashCode() Object clone() Object[] toArray() Object[] toArray(Object a[]) Methoden aus Object } Bemerkung: In Abschnitt 5.4.3 werden wir weitere eigenständige Bausteine kennen lernen. Im Allg. agieren Bausteine nicht eigenständig, sondern müssen mit anderen und andersartigen Bausteinen kooperieren, um ihre Funktionalität zu erbringen. Bausteine können eng oder nur lose kooperieren. Enge Kooperation findet man typischerweise in Programmgerüsten (engl. program frameworks). 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 679 Bemerkung: Die Kooperation zwischen Bausteinen kann man syntaktisch an den (rekursiven) Abhängigkeiten der Typdeklarationen erkennen. • Die Grenzen eines Bausteins werden vom Bausteinentwickler festgelegt und lassen sich im Allg. nicht aus dem Programmtext erschließen. • Die Unterscheidung zwischen den Bausteinarten ist nicht scharf. Beispiel: (Abhängigkeiten bei Kooperation) Folgende Fragmente stammen aus dem AWT (Pakete java.awt, etc.), einem Java-Framework zur Implementierung graphischer Bedienoberflächen. Begriffsklärung: (Programmierschnittstelle) class Component ... { ... void addComponentListener(ComponentListener c) ... } interface ComponentListener ... { ... void componentResized( ComponentEvent e ); ... } Die Programmierschnittstelle eines Bausteins (einer Komponente) besteht aus den öffentlichen Typen und Methoden, mit denen der Baustein aus Programmen heraus gesteuert werden kann. In gleicher Weise spricht man von der Programmierschnittstelle einer Anwendung oder eines Systems (engl. application programming interface, API). Beispiele: (Programmierschnittstellen) Es gibt Programmierschnittstellen für den: • Zugriff aufs Dateisystem class ComponentEvent ... { ... Component getComponent() ... ... } • Zugriff auf andere Teile des Betriebssystems • Zugriff aufs Netzwerk • Zugriff auf eine Anwendung, etwa ein Spiel 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 680 Bemerkung: 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern Wichtige Pakete der Java-Bibliothek Nicht alles, was sich API nennt, ist in obigem Sinne eine Programmierschnittstelle. Begriffsklärung: (Programmbibliothek) Eine Programmbibliothek oder einfach Bibliothek ist eine strukturierte Ansammlung von Programmteilen, die für die Wiederverwendung entwickelt und organisiert sind. Die Programmteile können unterschiedlicher Art sein (z.B. standardisierte Bausteine der Sprache, eigenständige Bausteine, Programmierschnittstellen, Programmgerüste). applet event awt font beans image io ref lang java math registry rmi Beispiele: (Programmbibliotheken) server • zu Programmiersprachen gehörende Bibliotheken (z.B. Java-Bibliothek) security • Bibliotheken für Datenstrukturen: STL, Leda, ... sql • Bibliotheken für graphische Bedienoberflächen, zu allgemeinen Anwendungsbaukästen text • Bibliotheken für Graphik, CAD, virtuelle Welten, ... util zip javax.* • Anwendungsspezifische Bibliotheken org. * © A. Poetzsch-Heffter, Universität Kaiserslautern reflection net nio 05.02.2007 681 682 05.02.2007 jar © A. Poetzsch-Heffter, Universität Kaiserslautern 683 Bemerkung: Es gibt drei Arten von Ausnahmesituationen: Die obige Darstellung der Java-Bibliothek ist unvollständig. Beispielsweise enthält das Paket javax.swing ein leistungsfähigeres Programmgerüst zur Realisierung graphischer Bedienoberflächen (GUI Framework). 1. Nicht korrigierbare Ausnahmesituationen (Error): Drei typische Beispiele: - kein Speicherplatz mehr verfügbar zum Erzeugen von Objekten (OutOfMemoryError) 5.4.2 Klassen zur Ausnahmebehandlung - zuviele unbeendete Methodenaufrufe (StackOverflowError) Realisierung der Ausnahmebehandlung in Java demonstriert zwei Aspekte: - Inkonsistenzen zwischen übersetzten Klassen (z.B. AbstractMethodError) - erweiterbare Hierarchie einfacher Bausteine - Zusammenspiel von Sprache und Standardbibliothek 2. Programmierfehler (RuntimeException): Typische Beispiele: Darüber hinaus ist das Verständnis der Ausnahmebehandlung von allgemeinem Interesse für die Softwareentwicklung. - Dereferenzieren von null (NullPointerException): Object ov = null; ov.equals( new Object() ); Klassifikation von Ausnahmesituationen - Feldzugriff mit unzulässigem Index (IndexOutOfBoundsException): Die möglichen Ausnahmesituationen werden in Java durch eine Typhierarchie klassifiziert. int[] iav = new int[37]; Alle Ausnahmeklassen sind Subklassen von java.lang.Throwable © A. Poetzsch-Heffter, Universität Kaiserslautern 05.02.2007 int n = iav[333]; 684 3. Nicht vermeidbare, aber behandelbare Situationen: Beispiele sind der Zugriff auf eine Ressource, etwa das Netz oder eine Datei, die augenblicklich anderweitig genutzt wird. 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 685 Insgesamt ergibt sich folgende Klassifikation bzw. Typhierarchie: Object Abhilfe: Throwable - zeitverzögert nochmaligen Zugriff - Anwendung einer vergleichbaren Ressource. Error Exception In diese Kategorie fallen auch die meisten anwendungsspezifischen Ausnahmen. IOException AbstractMethodError ClassNotFoundException OutOfMemoryError Beispiel: (anwendungsspez. Ausnahmekl.) KeinKaffeeException StackOverflowError public class KeinKaffeeException extends Exception { private float restMenge; RuntimeException KeinKaffeeException( float kaffeeMenge ){ restMenge = kaffeeMenge; NullPointerException } IndexOutOfBoundsException public float getRestMenge() { return restMenge; IllegalArgumentException } } NumberFormatException 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 686 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 687 Zusammenspiel von Sprache und Bibliothek 3. Aspekt: Behandlung von Ausnahmen: Die Ausnahmebehandlung in Java hat vier Aspekte: - im umfassenden try-Block; - Welche Ausnahmen gibt es? - die aktuelle Methode terminiert abrupt und reicht die Ausnahme an die Aufrufstelle weiter. - Wodurch werden Ausnahmen ausgelöst? - Wie werden Ausnahmen ggf. über Methodengrenzen hinweg weitergereicht? - Wie kann man Ausnahmen abfangen und behandeln? Der Java-Übersetzer prüft, welche Ausnahmen eine Methode möglicherweise auslöst, ohne sie abzufangen. Alle nicht-abgefangenen Ausnahmen, die weder Subklassen von Error noch von RunTimeException sind, müssen in der Signatur der Methode deklariert werden (siehe Beispiel). 1. Aspekt: In Java werden Ausnahmen als Subklassen von Throwable realisiert. D.h. - vordefinierte Ausnahmen in der Standardbibliothek 4. Aspekt: - benutzerdefinierte Ausnahmen als Subklassen Mittels der try-catch-Anweisung kann man Ausnahmen (und Fehler) abfangen: 2. Aspekt: try { Fehler und Laufzeitausnahmen werden durch das Laufzeitsystem von Java (Java Virtual Machine) ausgelöst. } catch( <Subtyp von Throwable> eb ) { <Anweisungsblock1> <Anweisungsblock2> } ... Andere Ausnahmen durch Systemschnittstellen oder Anwenderprogramme mittels der throw-Anweisung. Tritt im Anweisungsblock1 eine Ausnahme vom Typ E auf und ist E ein Subtyp des Typs, der in der catchKlausel genannt ist, dann wird die Ausnahme abgefangen und der Anweisungsblock2 ausgeführt. Der Ausdruck in der throw-Anweisung muss ein Subtyp von Throwable sein. © A. Poetzsch-Heffter, Universität Kaiserslautern 05.02.2007 688 Andernfalls wird die Ausnahme weitergereicht. Beispiel: ( Ausnahmebehandlung) public class KaffeeMaschine { private KaffeeSpeicher speicher; ... void fuellenFilter( float benoetigteMenge ) throws KeinKaffeeException { float restMenge; restMenge = speicher.messenFuellung(); if( restMenge < benoetigteMenge ) { throw new KeinKaffeeException(restMenge); } ... } } Bemerkung: • Häufig kann die Behandlung der Ausnahme erst von einem weiter außen liegenden Aufrufer erledigt werden. • Eine überschreibende Methode darf nur die Ausnahmen auslösen, die auch die überschriebene Methode auslösen darf. 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 690 05.02.2007 © A. Poetzsch-Heffter, Universität Kaiserslautern 689