Java Collection Framework

Willemers Informatik-Ecke

Zurück zu Java

In einem Programm werden oft mehrere Exemplare einer Klasse verarbeitet. Diese müssen in irgendwelchen Behältern organisiert werden. Ein Beispiel für einen solchen Behälter haben wir mit dem Array schon kennengelernt. Für viele Zwecke ist ein Array allerdings zu unflexibel. So bauen sich Programmierer immer wieder ihre eigenen Strukturen, die dann immer wieder neue Fehler enthalten und nicht immer effizient sind. Um hier zu helfen, bietet Java Datenbehälter an, die Standardsituationen beherrschen, erprobt und performant laufen.

Java fasst die von ihm angebotenen Datenbehälter im Java Collection Framework zusammen. Neben den eigentlichen Datenbehältern gehören auch noch Standardoperationen wie beispielsweise eine Sortierung dazu, die auf den Datenbehältern arbeiten. Sie werden als Algorithmen bezeichnet.

Den Programmierer interessiert natürlich zunächst, was er einfach importieren und benutzen kann, also die Implementierung der Datenbehälter.

Listen

ArrayList

Am dichtesten an einem Array ist die ArrayList. Wie beim Array stehen die Elemente dicht bei dicht nebeneinander und können schnell über ihre Position angesprochen werden. Im Gegensatz zum Array kann es beliebig erweitert werden.

LinkedList

Wenn die Elemente nicht in erster Linie über ihre Position angesprochen werden, sondern meist am Anfang oder am Ende Elemente angefügt werden, ist die LinkedList der bessere Kandidat. Damit lassen sich Queues (Warteschlangen) oder Stacks (Stapel) realisieren.

Mengen

Ein Set ist eine Menge. Hier ist nicht der schnelle Zugriff gefragt, sondern die Frage, ob bestimmte Elemente in der Menge enthalten sind. Ein Set stellt sicher, dass keine Doppelten enthalten sind.

HashSet implementiert sehr effizient das Interface Set. TreeSet wird eingesetzt, wenn eine sortierte Reihenfolge wichtig ist.

Assoziativer Speicher

HashMap

Assoziative Speicher ermöglichen den direkten Zugriff über einen Schlüssel auf das Element. Das Array ist ein sehr einfaches Beispiel. Allerdings erfordert das Array, dass der Schlüssel eine Zahl ist, bei 0 beginnt und immer um 1 erhöht wird. Eine HashMap kennt diese Einschränkungen nicht.

Interfaces

Interfaces enthalten selbst keine Implementierung, sondern geben vor, welche Methoden eine Implementierung zur Verfügung stellen muss und geben damit den Charakter vor. Die Collections implementieren vor allem folgende Interfaces:
  • Interface: Collection und Iterator
  • Um die Daten eines Datenbehälters auszulesen, bieten sie einen Iterator an, der zunächst auf das erste Element zeigt. Mit diesen kann man durch den Container laufen und alle Elemente auslesen.
  • Das Interface List
  • ArrayList und Vector implementieren das Interface List. Die Grundidee ist ein dynamisches Array, das bei Bedarf wachsen kann.
  • Das Interface Queue
  • LinkedList implementiert sowohl das Interface List als auch das Interface Queue.
  • Das Interface Set
  • HashSet implementiert das Interface Set.
  • Das Interface Map
  • HashMap implementiert das Interface Map.

Die Algorithmen des Java Collection Framework

Die Datenbehälter bringen ihre eigenen Methoden mit. Aber es gibt eine Reihe von Algorithmen, die sich auf alle Datenbehälter anwenden lassen. Beispielsweise eine Sortierung oder das Umdrehen der Reihenfolge. Zu diesem Zweck gibt es Algorithmen, die von der Klasse Collection zur Verfügung gestellt werden.

Typsicherheit durch Generics

In den ersten Varianten der Container wurde Object als Stellvertreter der Elemente verwendet. Das Problem war, dass der Compiler nicht kontrollieren konnte, wenn ein Programmierer versehentlich das Objekt einer anderen Klasse herausholte, als er ursprünglich hineingesteckt hatte. Um die Typsicherheit zu gewährleisten, wurden mit Java 5 die Generics entwickelt.

Ohne Generics verwalten die Collections einfach Objekte vom Typ Object. Da Object die Mutter aller Klassen sind, dürfen auch verschiedene Objekte hineingesteckt werden. Beim Herausholen der Objekte muss gecastet werden und es liegt in der Verantwortung des Programmierers, ob er das richtig macht.

private class Datum {
    int jahr, monat, tag;
    Datum(int j, int m, int t) {
        jahr=j; monat=m; tag=t;
    }
}

// ...

ArrayList feld = new ArrayList();
feld.add(new Datum(1960,4,24));
feld.add(new Datum(1969,3,17));
feld.add("Anton ist doof!");  // Das gibt Ärger!
for (int i=0; i<feld.size(); i++) {
   Datum datum = (Datum)feld.get(i);
   System.out.println(datum.jahr);
}
Durch spitze Klammern (Kleiner-, Größerzeichen) kann der ArrayList nun mitgeteilt werden, dass sie Objekte vom Typ Datum verwaltet und nicht einfach Objekte. So kann der Compiler überprüfen, ob das, was rein geht auch wieder rauskommt.

So ist es auch möglich, eine verkürzte for-Schleife speziell für Datenbehälter zu schaffen, die ohne Index einfach alle Elemente der Collection durchläuft.

ArrayList<Datum> feld = new ArrayList<Datum>();
feld.add(new Datum(1960,4,24));
feld.add(new Datum(1969,3,17));
for (Datum datum : feld) {
    System.out.println(datum.jahr);
}


Homepage - Java (C) Copyright 2011, 2016 Arnold Willemer