Springe zum Inhalt

Java Collections

Die sogenannten Collection-Klassen (auch Aggregate oder Container) stellen eine Sammlung von Daten oder Objekten in einer sog. Datenstruktur dar. Sie werden verwendet um bei der Programmausführung transiente (nicht persistent gespeicherte) Daten im Arbeitsspeicher zu halten. In diesem Zusammenhang dürfte den meisten Lesern das Array schon bekannt sein, welches jedoch, im Gegensatz zu den Collections, teil der Sprachdefinition von Java ist.  Da Arrays jedoch verschiedenen Einschränkungen unterworfen sind bietet die Java-Klassenbibliothek im Paket java.util die Collections zur Verwendung an.

Die Vorteile gegenüber dem Array und den konkreten Einsatz der Java-Collections möchte ich in diesem Artikel mit dem nötigsten an Theorie und ein wenig Beispielcode veranschaulichen. Außerdem werde ich immer wieder auf die entsprechenden Seiten der Java-Klassenbibliothek verweisen, sodass Sie sich einen schnellen Überblick über die Methoden verschaffen können.

Überblick über die Collection-API

Prinzipiell lassen sich in Java vier unterschiedliche Arten von Datenstrukturen unterscheiden, denen jeweils verschiedne Designprinzipien zugrunde liegen.

  • Listen
  • Queues
  • Sets
  • Maps

Dabei haben diese vier Datenstrukturen eine gemeinsame Wurzelschnittstelle, das Interface java.util.Collection<E> das seinerseits wiederum das Interface java.lang.Iterable<T> implementiert (bis auf die Map wie wir später sehen werden). Durch die Schnittstelle Iterable besitzen die Klassen eine Iterator-Methode die es ermöglicht alle Objekte einer Collection nacheinander und einzeln zuzugreifen (siehe Artikel zum iterieren über Java Collections).

Wichtige Methoden der Schnittstelle java.util.Collection<E> sind:

  • boolean add(E e) – fügt ein Object vom generischen Typen <E> hinzu
  • void clear() – entfernt alle Objekte
  • boolean contains(Object o) – prüft ob ein spezifisches Objekt enthalten ist
  • boolean equals(Object o) – prüft auf Gleichheit zwischen dem übergebenen Objekt und der Collection
  • boolean isEmpty() – prüft ob Elemente keine Elemente vorhanden sind
  • Iterator <T> iterator() – eine Methode die vom Interface Iterable<T> geerbt wurde und ermöglicht einen Iterator zu erzeugen der über die Datenstruktur iteriert
  • boolean remove(Object o) – entfernen eines spezifischen Objekts
  • int size() – gibt die Anzahl der enthaltenen Objekte zurück
  • Object[] toArray – gibt ein Array vom Typ Object mit allen enthaltenen Elementen der Datenstruktur zurück

Listen (Lists)

Listen sind geordnete Datenstrukturen. Der Zugriff kann über einen Index an beliebiger Stelle erfolgen, wie vermutlich vom klassischen Array bekannt. Im Gegensatz zu Arrays können in die Liste jedoch Objekte einfach an beliebiger Stelle eingefügt werden ohne dabei manuell eine neue Datenstruktur mit angepasster Größe anlegen zu müssen. Sie wachsen also dynamisch.

Generell lassen sich vier Typen von Listen unterscheiden die die Funtkionalität der Liste intern unterschiedlich implementieren.

  • ArrayList
  • LinkedList
  • Vector
  • Stack

Dabei realisiert die LinkedList die Datenstruktur intern über eine Verknüpfung von Zeigern, während die anderen Listentypen intern ein Array verwenden und beim Hinzufügen eines Objektes ein neues Array erzeugen und alle Elemente hinein kopieren.

Alle Java-Listen implementieren das Interface List<E> in ihren abstrakten Basisklassen AbstractList (für ArrayList, Vector und Stack) und AbstractSequentialList (für die LinkedList) von denen wiederum die konkreten Klassen abgeleitet sind, diese also beerben.

Codebeispiel für Erzeugung einer List

Beispielcode - Erzeugung einer Java-LinkedList
import java.util.*; //importieren des Paketes util
public class ListBeispiel {

	public static void main(String []args){
		//Liste erzegen und 2 Elemente anhängen
		List<String> liste=new LinkedList <String>(); //erzeugen der Liste
		liste.add("Hans Frieder"); //hinzufügen von Stringobjekten am Ende der Liste
		liste.add("Peter Maffay");

		System.out.println(liste);
		
		liste.add(1, "Rotzlöffel"); //hinzufügen mit Index
		System.out.println(liste);
		
		liste.set(0, "Lucky Luke");
		System.out.println(liste.get(1));//Zugriff auf das Objekt mit Index 1 und Ausgabe 
	}
}

Warteschlangen (Queues)

Die Warteschlange ist im Prinzip auch eine Liste, die Objekte jedoch nach dem FIFO Prinzip (First In First Out) abarbeitet. Die Möglichkeit für den Zugriff auf ein Objekt besteht ausschliesslich am Anfang und am Ende der Warteschlange und ist somit nicht wahlfrei möglich.

Die Schnittstelle Queue<E> wird von der Klasse AbstractQueue<E> implementiert welches die folgenden Warteschleifen-Klassen beerbt:

  • PriorityQueue
  • PriorityBlockingQueue
  • LinkedBlockingQueue

Dabei ist zu beachten dass die „BlockingQueues“ nochmal zusätzlich die Schnittstelle BlockingQueue<E> implementieren.

Codebeispiel – Verwendung einer Java-Queue

import java.util.*;
public class Queue_Beispiel {

	
	public static void main(String[] args) {
		//Collections erlauben nur Objekte, daher die erwendung von Wrappertypen wie Integer statt int
		PriorityQueue<Integer>intQueue=new PriorityQueue<Integer>(); 
		//Objekte hinzufügen
		intQueue.add(1);
		intQueue.add(2);
		intQueue.add(3);
		intQueue.add(4);
		//Zugriff aud das oberste/erste Objekt der Warteschlange (Element bleibt in der Queue)
		int var=intQueue.element(); //auto unboxing und binden an den Primitivdatentyp int
		
		//Zugriff und entfernen des ersten -objekts der Queue
		intQueue.poll();
		
		//Ausgeben der Anzahl an Elementen die die Queue enthält
		intQueue.size();
		
		//Alle Elemente der Queue entfernen
		intQueue.clear();
		
		//Übernehmen aller Objekte aus einer anderen Collection
		intQueue.addAll(andereCollection);
		
		//Schreiben aller Elemente in eine andere Collection
		intQueue.removeAll(andereCollection);
	}

}

Mengen (Sets)

Sets sind im Grunde eher mit mathematischen Mengen vergleichbar als mit einer listenartigen Struktur. Sie sind ungeordnet und erlauben keine Duplikate von Objekten (Einzigartigkeit). Im wesentlichen beschränken sich die Zugriffsmethoden auf das Hinzufügen, das Entfernen und das Prüfen ob ein bestimmtes Objekt enthalten ist.

Bezüglich der Einzigartigkeit sollte beachtet werden, dass die Gleichheit zweier Objekte mit der geerbten Methode equals(Objekt o) geprüft wird (siehe oben, Beschreibung der Schnittstelle Collection). Wird diese Methode für den Objekttyp, den die Menge enthält, nicht überschrieben, so sind alle immer Objekte unterschiedlich, auch wenn sie die gleichen Attributwerte tragen. Dies gilt nicht für Primitivdatentypen deren Gleichheit durch die Methode in jedem Fall geprüft werden kann. Da hierzu wieder ein wenig mehr zu sagen ist, werde ich einen eigenen Artikel zu diesem Thema verfassen und solange an dieser Stelle an die geeignete Fachliteratur verweisen.

Die Schnittstelle Set<E> wird von der abstrakten Basisklasse AbstractSet<E> implementiert und diese wiederum beerbt die folgenden Klassen

  • HashSet
  • EnumSet
  • TreeSet

Verzeichnisse (Maps)

Maps, auch Assoziative Felder genannt, bilden Slüssel auf Werte ab, wobei der Schlüssel eindeutig sein muss und für den Zugriff verwendet wird. Somit wird statt einem numerischen Index über ein eindeutiges Schlüsselobjekt auf die Werte der Map zugegriffen. Ähnlich einer Menge werden die Objekte im Verzeichnis ungeordnet gehalten. Die Reihenfolge spielt hier also keine Rolle.

Da in ein Verzeichnis immer zwei Objekte eingefügt werden implementieren sie nicht die Schnittstelle Collection<E>, die auf zwei Übergabeparameter nicht vorbereitet ist, sondern die Schnittstelle Map<K,V>. Die Schnittstelle wird wiederum von der abstrakten Basisklasse AbstractMap<K,V> implementiert, welche Ihrerseits folgende Verzeichnis-Klassen beerbt:

  • EnumMap
  • TreeMap
  • HashMap
Veröffentlicht inJavaTechnik und Technologie

Sei der Erste der einen Kommentar abgibt

Schreibe einen Kommentar