• Keine Ergebnisse gefunden

Prof. Dr. Uwe Aßmann Lehrstuhl Softwaretechnologie Fakultät für Informatik

N/A
N/A
Protected

Academic year: 2021

Aktie "Prof. Dr. Uwe Aßmann Lehrstuhl Softwaretechnologie Fakultät für Informatik"

Copied!
5
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Softwaretechnologie, © Prof. Uwe Aßmann

Technische Universität Dresden, Fakultät Informatik 1

12) Generische Datenstrukturen

Prof. Dr. Uwe Aßmann Lehrstuhl Softwaretechnologie Fakultät für Informatik

TU Dresden Version 11-0.1, 07.05.11

Prof. U. Aßmann, Softwaretechnologie 2

Empfohlene Literatur

http://download.oracle.com/javase/6/docs/

Tutorials http://download.oracle.com/javase/tutorial/

Generics Tutorial:

http://download.oracle.com/javase/tutorial/extra/generics/index.html

2 Trends in der Softwareentwicklung

Rapid Application Development (RAD)

Schneller viel Code schreiben

Typisierung weglassen

♦ Bei den Assoziationen

♦ Beim Programmieren gegen Schnittstellen

Ev. dynamische Typisierung, damit Fehler zur Laufzeit identifiziert werden können

Mächtige Operationen, die schnell zu schreiben sind

Safe Application Development (SAD)

Guten, stabilen, wartbaren Code schreiben

Statische Typisierung, damit der Übersetzer viele Fehler entdeckt

Mehr Entwurfswissen aus dem Entwurf in die Implementierung übertragen

Aus der Definition einer Datenstruktur können Bedingungen für ihre Anwendung abgeleitet werden

Gradual Typing

Typen werden Schritt für Schritt annotiert

Zeit

Zuverlässigkeit groovy

Java Java 1.6

Bsp.: Elemente einer Hierarchie

Formular

Bestellung Lieferschein Rechnung

(2)

Prof. U. Aßmann, Softwaretechnologie 5

Problem 1 ungetypter Schnittstellen:

Laufzeitfehler

Bei der Konstruktion von Collections werden oft Fehler programmiert, die bei der Dekonstruktion zu Laufzeitfehlern führen

Kann in Java < 1.5 nicht durch den Übersetzer entdeckt werden

List listOfRechnung = new ArrayList();

Rechnung rechnung = new Rechnung();

listOfRechnung.add(rechnung);

Bestellung best = new Bestellung();

listOfRechnung.add(best);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i);

}

List listOfRechnung = new ArrayList();

Rechnung rechnung = new Rechnung();

listOfRechnung.add(rechnung);

Bestellung best = new Bestellung();

listOfRechnung.add(best);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i);

}

Programmierfehler!

Laufzeitfehler!!

Prof. U. Aßmann, Softwaretechnologie 6

Problem 2 ungetypter Schnittstellen: Unnötige Casts

Bei der Dekonstruktion von Collections müssen unnötig Casts spezifiziert werden

Typisierte Collections erhöhen die Lesbarkeit, da sie mehr Information geben

List listOfRechnung = new ArrayList();

Rechnung rechnung = new Rechnung();

listOfRechnung.add(rechnung);

Rechnung rechnung2 = new Rechnung();

listOfRechnung.add(rechnung2);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i);

}

List listOfRechnung = new ArrayList();

Rechnung rechnung = new Rechnung();

listOfRechnung.add(rechnung);

Rechnung rechnung2 = new Rechnung();

listOfRechnung.add(rechnung2);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i);

}

Diesmal ok

Cast nötig, obwohl alles Rechnungen

Abhilfe: Generische Klassen

In UML

Eine generische Klasse ist eine Klassenschablone, die mit einem Typparameter P versehen ist.

Eine generische Klasse ist eine Klassenschablone, die mit einem Typparameter P versehen ist.

In Java

Sprachregelung: “Container of P”

P

class Container<P> { P content[];

}

Container

content P

Generische Datentypen in der Collection- Hierarchie

Die generische Collection-Hierarchie (seit Java 1.5)

E: Element, K: Key, V: Value

E Collection

E List

E Set

E Queue

K,V Map

E K,V SortedSet

Blocking E

(3)

Prof. U. Aßmann, Softwaretechnologie 9

Instanz der Generischen Hierarchie

Darf man Rechnungen, Bestellungen und Lieferscheine in diese Collections stecken?

Ja.

Collection

<Formular>

List

<Formular> Set

<Formular>

Queue

<Formular> Map

<Nr,Formular>

SortedMap

<Nr,Formular>

SortedSet

<Formular>

Blocking Queue

<Formular>

E Collection

E List

E Set

E Queue

K,V Map

K,V SortedMap E

SortedSet

Blocking E Queue

<<instantiates>>

Prof. U. Aßmann, Softwaretechnologie 10

Probleme gelöst

Bei der Konstruktion von Collections werden jetzt Äpfel von Birnen unterschieden

Casts sind nicht nötig, der Übersetzer kennt den feineren Typ

List<Rechnung> listOfRechnung = new ArrayList<Rechnung>();

Rechnung rechnung = new Rechnung();

listOfRechnung.add(rechnung);

Bestellung best = new Bestellung();

listOfRechnung.add(best);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = listOfRechnung.get(i);

}

List<Rechnung> listOfRechnung = new ArrayList<Rechnung>();

Rechnung rechnung = new Rechnung();

listOfRechnung.add(rechnung);

Bestellung best = new Bestellung();

listOfRechnung.add(best);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = listOfRechnung.get(i);

}

Compilerfehler

Kein Cast mehr nötig

Generizität funktioniert auch geschachtelt

// Das Archiv fasst alle Rechnungen aller bisherigen Jahrgänge zusammen List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>();

// listOfRechnung fasst die Rechnungen des aktuellen Jahres zusammen List<Rechnung> listOfRechnung = new ArrayList<Rechnung>();

archiv.add(listOfRechnung);

Rechnung rechnung = new Rechnung();

archiv.getIndex(0).add(rechnung);

Bestellung best = new Bestellung();

archiv.getIndex(0).add(best);

for (int jahr = 0; jahr < archiv.size(); jahr++) { listOfRechnung = archiv.getIndex(jahr);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = listOfRechnung.getIndex(i);

} }

// Das Archiv fasst alle Rechnungen aller bisherigen Jahrgänge zusammen List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>();

// listOfRechnung fasst die Rechnungen des aktuellen Jahres zusammen List<Rechnung> listOfRechnung = new ArrayList<Rechnung>();

archiv.add(listOfRechnung);

Rechnung rechnung = new Rechnung();

archiv.getIndex(0).add(rechnung);

Bestellung best = new Bestellung();

archiv.getIndex(0).add(best);

for (int jahr = 0; jahr < archiv.size(); jahr++) { listOfRechnung = archiv.getIndex(jahr);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = listOfRechnung.getIndex(i);

} }

funktioniert

Übersetzungs- Fehler

Benutzung von getypten und ungetypten Schnittstellen

.. ist ab Java 1.5 ohne Probleme nebeneinander möglich

// Das Archiv fasst alle Rechnungen aller bisherigen Jahrgänge zusammen List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>();

// listOfRechnung fasst die Rechnungen des aktuellen Jahres zusammen List listOfRechnung = new ArrayList();

archiv.add(listOfRechnung);

Rechnung rechnung = new Rechnung();

archiv.getIndex(0).add(rechnung);

Bestellung best = new Bestellung();

archiv.getIndex(0).add(best);

for (int jahr = 0; jahr < archiv.size(); jahr++) { listOfRechnung = archiv.getIndex(jahr);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.getIndex(i);

} }

// Das Archiv fasst alle Rechnungen aller bisherigen Jahrgänge zusammen List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>();

// listOfRechnung fasst die Rechnungen des aktuellen Jahres zusammen List listOfRechnung = new ArrayList();

archiv.add(listOfRechnung);

Rechnung rechnung = new Rechnung();

archiv.getIndex(0).add(rechnung);

Bestellung best = new Bestellung();

archiv.getIndex(0).add(best);

for (int jahr = 0; jahr < archiv.size(); jahr++) { listOfRechnung = archiv.getIndex(jahr);

for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.getIndex(i);

} }

funktioniert

Übersetzt auch, aber Laufzeitfehler

beim Cast...

(4)

Prof. U. Aßmann, Softwaretechnologie 13

Typschranken generischer Parameter (type bounds)

Beispiel: Comparable<E> als Return-typ in der Collections-Klasse sichert zu, dass die Methode compareTo() existiert

class Collections {

/** minimum function for a Collection. Return value is typed * with a generic type with a type bound */

public static <E extends Comparable<E>> min(Collection<E> ce) { Iterator<E> iter = ce.iterator();

E curMin = iter.next;

if (curMin == null) return curMin;

for (E element = curMin;

iter.hasNext(), element = iter.next) { if (element.compareTo(curMin) < 0) {

curMin = element;

} }

return curMin;

}

class Collections {

/** minimum function for a Collection. Return value is typed * with a generic type with a type bound */

public static <E extends Comparable<E>> min(Collection<E> ce) { Iterator<E> iter = ce.iterator();

E curMin = iter.next;

if (curMin == null) return curMin;

for (E element = curMin;

iter.hasNext(), element = iter.next) { if (element.compareTo(curMin) < 0) {

curMin = element;

} }

return curMin;

}

Prof. U. Aßmann, Softwaretechnologie 14

Implementierungsmuster Command:

Generische Methoden als Funktionale Objekte

Funktionalobjekte können Berechnungen kapseln und später ausführen (laziness) (Entwurfsmuster Command)

Es gibt eine Standard-Funktion in der Klasse des Funktionalobjektes, das die Berechnung ausführt (Standard-Name, z.B. execute() oder doIt())

Zur Laufzeit kann man das Funktionalobjekt mit Parametern versehen, herumreichen, und zum Schluss ausführen

Ein Funktionalobjekt (Kommandoobjekt) ist ein Objekt, das eine Funktion darstellt (reifiziert).

Ein Funktionalobjekt (Kommandoobjekt) ist ein Objekt, das eine Funktion darstellt (reifiziert).

// A functional object that is like a constant interface NullaryOpCommand { void execute(); } // A functional object that takes one parameter interface UnaryOpCommand<P> { P execute(P p1); } // A functional object that operates on two parameters interface BinOp<P> { P execute(P p1, P p2); }

// A functional object that is like a constant interface NullaryOpCommand { void execute(); } // A functional object that takes one parameter interface UnaryOpCommand<P> { P execute(P p1); } // A functional object that operates on two parameters interface BinOp<P> { P execute(P p1, P p2); }

Generische Methoden als Funktionale Objekte

Anwendung: Akkumulatoren und andere generische Listenoperationen

// An interface for a collection of binary operation on // collections

interface Functional<Collection<P>,B extends BinOp<P>> { P compute(Collection<P> p);

}

class Accumulate<C,E> implements Functional<C,BinOp<E>> { E curSum; E element; BinOp<E> binaryOperation;

public E compute(C coll) {

for (int i = 0; i < coll.size(); i++) { element = coll.getIndex(i);

curSum = binaryOperation.execute(curSum,element);

}

return curSum;

}}

// An interface for a collection of binary operation on // collections

interface Functional<Collection<P>,B extends BinOp<P>> { P compute(Collection<P> p);

}class Accumulate<C,E> implements Functional<C,BinOp<E>> { E curSum; E element; BinOp<E> binaryOperation;

public E compute(C coll) {

for (int i = 0; i < coll.size(); i++) { element = coll.getIndex(i);

curSum = binaryOperation.execute(curSum,element);

}

return curSum;

} } P BinOp

Collection

<P>

Functional

C,E Accumulate

B

Unterschiede zu C++

In Java: einmalige Übersetzung des generischen Datentyps

Verliert etwas Effizienz, da der Übersetzer alle Typinformation im generierten Code vergisst und nicht ausnutzt

z.B. sind alle Instanzen mit unboxed objects als boxed objects realisiert

C++ bietet Code-Templates (snippets, fragments) an, mit denen man mehr parameterisieren kann, z.B. Methoden

In C++ können Templateparameter Variablen umbenennen:

template class C <class T> { T attribute<T>

} Templateparameter können Variablen umbenennen

(5)

Prof. U. Aßmann, Softwaretechnologie 17

Was haben wir gelernt

Static vs. dynamic vs. gradual vs. no typing

Generische Datenstrukturen sind Klassenschablonen mit Typ- Parameter

Feinere statische Typisierung möglich

Generische Collections besitzen den Element-Typ als Typ-Parameter

Element-Typ verfeinert Object

Weniger Casts, mehr Typsicherheit

Implementierungsmuster Command

Prof. U. Aßmann, Softwaretechnologie 18

End

Referenzen

ÄHNLICHE DOKUMENTE

Innerhalb der Kindergruppe und innerhalb der Erwachsenengruppe zeigen sich bei der Kondylenbahnlänge des rechten Condylus keine signifikanten Unterschiede zwischen

Wir konnten zeigen, dass die Applikation einer Kraft (2 g/cm²) genauso wie der Zusatz von Bakterien eine erhöhte Expression von OPG und RANKL im Vergleich zu deren physiologischer

Diese Studie konnte bestätigen, dass zwei und mehr Nichtanlagen in einem Kiefer eine negative Auswirkung auf den Prognathiegrad desselben Kiefers haben, wobei dies

In mehreren Studien konnte nachgewiesen werden, dass die katabolischen Effekte auf den Knorpel unter anderem über eine Hemmung der die Chondrogenese fördernden Faktoren TGF-ß

 Haskell kann für Informatiker einen sehr guten Einstieg in das Studium darstellen.  Es gibt Anwendungsgebiete in denen Haskell durchaus die Sprache der

Prof. Uwe Aßmann Lehrstuhl Softwaretechnologie Fakultät für Informatik.. TU Dresden

► Der Architekturstil Geschichtete Lebenszyklen (geschichtete Steuerungsmaschinen, abstrakte Maschinen, Layered Abstract Machines) benutzt punktweise Verfeinerung, um höher liegende

► Ersetze alle “integrates”, “plays”, “mandatory-part”, etc. durch Vererbung. ► Einfach, allerdings braucht man Mehrfachvererbung oder