uio--WebPageMain-Module

JAVA-B2 Collections Collections Framework Diagramm Was sind Collections Vorteile

Collection Interfaces Core-Collection-Interfaces (Begriff, Ziele, Standard) Liste der Core Interfaces List Set Queue Dequeue SortedSet NavigableSet Map SortedMap NavigableMap Collections Zusammenfassung @!Beispiele+Links

Das Interface Collection Das Superinterface Diagramm Diagramm Collection-Standard-Methoden Zusammenfassung

Implementierungsklassen Implementierungsklassen Diagramm Array[T]> Lists ArrayList<E> LinkedList<E> CopyWriteOnList<E> Set<E> Implementations HashSet<E> TreeSet<E> EnumSet<E> CopyWriteOnArraySet<E> Queue<E> Implementations LinkedList<E> PriorityQueue<E> Deque<E> Implementations LinkedList<E> ArrayDeque<E> Map<E> Implementations HashMap<K,V> LinkedHashMap<K,V> TreeMap<K,V> WeakHashMap<K,V> IdentityHashMap<K,V> EnumMap<K,V> ConcurrentHashMap<K,V>** ConcurrentSkipList<K,V>** SortedSet<E> Implementations TreeSet<E> EnumSet<E> BlockingQueue<E> Implementations ArrayBlockingQueue<E> LinkedBlockingQueue<E> LinkedBlockingQueue<E> PriorityBlockingQueue<E> SynchronousQueue<E> DelayQueue<E> Legacy Types für Listen Vector Hashtable Stack Stack HashSet<E> HashSet<E> @!Descriptions @!Examples @!Index/Examples

Overview

Interface Collection | Overview

Das Interface «Collection» ist das Superinterface für alle weiteren Interfaces im Java Collection Framework und stellt dahingehend mit seinen Methoden auch den Standard für alle Implementierungsklassen dar.

Seit Java 8 wurde im Zusammenhang mit dem Java Collection Framework die Stream API eingeführt und für alle Implementierungklassen über das Collection-Interface durchgesetzt. Das Verständnis dieses Interfaces Collection ist die zwingende Voraussetzung für das Verständnis der Nutzer der übrigen Interfaces und Klassen.

Super-Interface

Collection | Super-Interface

Die Kenntnis und ein Verständnis der Methoden dieses Super-Interface Collection<E ist bedeutsam für die Vermeidung von Programmierfehler und Denkfehlern.

Maßgebend für den grundlegenden Einstieg wird ein Verständnis der Bedeutung der von Collection abgeleiteten Interfaces wie mitunter List, Set oder Map sein. Auf diese wird in einem eigenen Themenblock eingegangen werden.

Abbildung: Grafik mit JAVA Collection-Interfaces und JAVA Collection-Klassen sowie Informationen zur Implementierung und Erweiterung von Interfaces um andere Interfaces, SNEWMEDIA, 2025. {@ref}

Sinn & Zweck

Collection | Sinn & Zweck

Das Interface «Collection» ist das Super- oder Basis-Interface für alle anderen Interfaces in der Gruppe der Core-Collection-Interfaces. Alle Methoden, welche also das Collection-Interface vorgibt, werden von allen durch Java bereit gestellten Collections sichergestellt.

Die Kenntnis und ein Verständnis dieser Methoden ist entscheidend für das Verständnis und das fehlerfreie Arbeiten mit Collections in Java. So wird in diesem Themenblock auch erwähnt, wie man kontrolliert und verlässlich Elemente einer Collection mit Iteratoren entfernt, weil alle anderen Varianten zu Fehlern führen können.

Eine Collection repräsentiert eine Gruppe von Objekts. Objekte einer Gruppe bezeichnet hierbei als Elemente (engl. elements).

Maximale Vereinheitlich von Collections

Das Collection-Interface wird verwendet, um Gruppen von Objekten in einer Programmanwendung zwischen Methoden, Funktionen und Variablen transportieren zu können. Es ist deshalb gewollte, dass alle Collections nach dem selben Prinzip zu verstehen und zu nutzen sind.

Konvention: Konstruktor hat ein Collection Argument

Mit dem Ziel einer maximalen Vereinheitlichung aller Collection-Interfaces und damit auch dem Verhalten aller Implementierungsklassen wurde die Konvention geschaffen, dass eine jede Collection stets ein Konstruktur-Argument vom Typ Constructor besitzt.

Man bezeichnet das auch als Conversion-Constructor.

Conversion Constructor

Der Sinn und Zweck eines Konstruktorarguments vom Typ Collection besteht darin, dass eine jede Gruppe von Elementen, welche vom Objekt dieses Interfaces verwaltet werden soll, von Beginn an mit einer bestehenden Collection mit all deren Elementen initialisiert werden kann.

Egal, welchen Typ und damit welche Implementierungsklasse die im Konstruktor als Argument übergebene andere Collection mit dem einen oder anderen Collection-Sub-Interface auch gehabt hat: Eine jede Collection im Java-Collection-Framework ist in der Lage, die Gruppe der eigenen Elemente mit den Elementen der im Konstruktor gelieferten Elemente zu initialisieren.

Oder anders formuliert: Man kann mit Hilfe des Konstruktors einer jeden Collection und damit schlichtweg über die Verwendung von Collection-Interfaces vom Prinzip her den Typ einer Collection in einen anderen Typ ändern.

Beispiel: Umwandlung in ArrayList und List

Beispiel: Wenn wir irgendeine Collection von Vornamen haben sollten, so können wir diese Gruppe von String-Elementen allein über den Konstruktor der Klasse ArrayList in einen Typ umwandlen, welcher schlussendlich das List Interfaces implementiert hat.

Die ArrayList hat das dieses List-Interface implementiert.


 
 // List, Set, oder andere Collection
Collection<String> c = Data.getVornamen();
List<String> list = new ArrayList<String>(c);

// Ab Java 7 ist auch eine Kurznotation
// mit dem sogenannten Diamond-Operator möglich.
List<String> list = new ArrayList<>(c);

Methoden

Collection | Methoden des Collection-Interfaces

Eine jede Collection verfügt über einen Mindestumfang praktischer Methoden. Das Collection-Interface als Basis-Interface stellt sicher, dass jedes Interface eine Reihe von Methoden bereitstellt, so dass das Arbeiten mit jeder Collection egal welcher Implementierung immer gleich aussieht.

So lange eine Collection eine Gruppe von Objekten als Elemente beinhaltet, macht eine jede Collection aus dem Java Collection Framework exakt das, was man erwartet.

Wir können mit size() die Größe bestimmen und mit isEmpty() + erfahren, ob die Sammlung leer ist. Und mit contains() können wir prüfen, ob das Objekt schon enthalten ist.


 
int size() Anzahl der Elemente 
boolean isEmpty() Ist die Collection leer?
boolean contains(Object element) Ist dieses Objekt schon enthalten?

Die add() Methoden der Collections sind in der Lage, eigenständig zu erkennen, ob Gruppen auf doppelte Einträge geprüft und diese entfernt werden müssen oder ob diese Erhalten bleiben können, da manche Collections doppelte Elemente als Duplikate erlauben.

Die add() Methode der Collection stellt sicher, dass die Collection das Objekt bekommen wird, wenn es noch nicht bestand, und es haben wird, falls es bereits bestand und man das Objekt kein zweites Mal hinzugefügt hat, falls die Collection keine Dubplikate erlaubt. Add() liefert true wenn ein Element neu hinzugefügt wurde.

Auch die remove() Methode einer Collection ist so programmiert worden, dass Sie eine einzelne Instanz eines Objekts in der Collection entfernt. Wenn die Collection verändert wurde, liefert die remove() Methode true.


 
boolean add(E element) Hinzufügen eines Objekts als Element
boolean remove(Object element) Entfernen eines Objekts
Iterator<E> iterator() Iterator erhalten zum Durchlaufen aller Elemente.

Mit Hilfe eines Iterators, den wir über it=collection.iterator() bekommen, können wir über eine Abfolge von while, it.hasNext() und it.next() alle Elemente kontrolliert durchlaufen.


 
// Iterator erhalten zum Durchlaufen aller Elemente.
Iterator<E> iterator() 

Hinweis: Es wird bei größeren Datenmengen empfohlen, die mit Java 8 hinzugekommenen Aggregate-Operations in Verbindung mit stream und parallelStream zu verwenden. Diese benötigen weniger Speicherplatz, der Quellcode ist kürzer, die Lesbarkeit von Programmcode hat sich verbessert, die Performance steigt und eine Reihe von Problemstellungen wurden entschärft.


 
Methoden als Operationen für komplette Collections.

boolean containsAll(Collection<?> c) Sind alle Elemente enthalten?
boolean addAll(Collection<? extends E> c) Komplette Gruppe hinzufügen
boolean removeAll(Collection<?> c) Elemente dieser Gruppe enfernen
boolean retainAll(Collection<?> c) 
void clear() Alle Elemente der Gruppe löschen.



 
Operationen für Umwandlung von Collections in Arrays. Dieses wird oft
für die Konvertierung von Datenstrukturen für die Nutzung alter APIs verwendet,
welche noch mit Arrays und nicht mit Collections arbeiten..

Object[] toArray() Umwandeln der Collection in einen Object-Array
<T> T[] toArray(T[] a) Exportieren aller Elemente in einen Array des Typs T

Ab Java 8 wurden weitere Methoden im Zusammenhang mit Streams ermöglicht. Damit ist eine sequentielle Verarbeitung aller Elemente der Gruppe ebenso möglich wie eine parallele Verarbeitung. Mehr hierzu siehe: Aggregate Operations, Using Streams mit Stream<E> stream() und Stream<E> parallelStream().

Wer auch weiterhin gern wie in anderen Programmiersprachen wie in JavaScript oder PHP gern seine Elemente in Gruppen selbst verwalten will, kann das zwar auch in Java weiterhin machen. Die Realität sieht aber in Java so aus, dass alle Packages, die von Java selbst kommen, bereits konsequent Collections und entsprechende Interfaces verwenden. Man kommt am Java Collection Framework als faktisch nicht vorbei.

Traversing Collections

Für das Durchlaufen aller Elemente, die als Gruppe in einem Container-Objekt enthalten sind, dessen Typ das Collection-Interface implementiert hat, ist mitunter über 3 Varianten möglich: Aggregate-Operations, For-Each-Konstrukte und durch die Verwendung eines Iterators.

Die ab Java 8 empfohlende und dahingend auch übliche Variante über die Iteration über alle Elemente einer Collection ist die Beschaffung eines Streams mit anschließender Verwendung von Aggregate-Operationen.

Streams, Lambdas und Aggregate-Operations ab Java 8

Eine AggregateOperation wird zumeist in Verbindung mit Lambda-Expressions realisiert. Der zugehörige Programmcode ist oft lesbare, benötigt weniger Code-Zeilen und ist damit leichter verständlich. The following code sequentially iterates through a collection of shapes and prints out the red objects:

Das nachfolgende Beispiel zeigt, man sich für eine Collection zuerst einen stream über die stream() Methode beschafft.

Beim Durchlaufen der Sequenz aller Elemente wird der Strom von Elementen über die filter() Funktion auf die Elemente reduziert, welche die als Predicate e->e.getColor()==Color.RED formulierte Bedingng erfüllen.

Der letztendlich vom Filter durchgelassene Strom von Elementen wird dann Element für Element mit Hilfe der forEach(..) Aggregate-Operation auf der Konsole ausgeben.


 
farbenFormenCollection.stream()
 .filter(e -> e.getColor() == Color.RED)
 .forEach(e -> System.out.println(e.getName()));

Es ist auch eine nebenläufige Variante mit parallelStream möglich.

Im Falle sehr großer Datenmengen und der Verfügbarkeit eines Rechners mit mehreren Prozessoren ist leicht möglich, die Verarbeitung aller Elemente einer Collection ohne die manuelle Programmierung von Threads und Runnables sehr einfach über die parallelStream() Methode zu ermöglichen, über welche alle Collections des Java Collection Frameworks verfügen.


 
farbenFormenCollection.parallelStream()
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));

Hinweis: In Bezug auf die parallele Verarbeitung von Elementen und die Programmierung von Lambda-Expressions gilt es eine ganze Reihe von Aspekten zu berücksichtigen, so dass wir für dieses Thema eigene Themenblöcke und Kapitel geschaffen haben.

stream, map, collect, joining

Eine häufige Problemstellung besteht darin, eine Liste aller Werte als String zu erhalten und die Elemente hier bei durch einen Separator, beispielsweise ein Komma, zu trennen.


 
String joined = elements.stream()
 .map(Object::toString)
 .collect(Collectors.joining(", "));

Die stream-Methode liefert uns eine Sequenz von Elementen, ein Element nach dem anderen.

Um jedes Element der Liste in einen String umzuwandeln, soll jedes Element-Objekt der Liste durch die toString(element) Methode verarbeitet werden. Die map(..) Methode erstellt also eine Map, wobei hierfür eine Referenz auf eine Methode erforderlich ist.

Anstelle der Programmierung eines Lambda-Ausdrücks können also auch Referenzen auf Methoden programmiert werden.

Mit Hilfe der Aggregate-Operation collect(..) wird nun ein Rückgabewert vom Typ String durch die Collectors.joining(", ") Methode realisiert. Da diese aber wissen muss, welcher Separator verwendet wird, wird dieser noch in Klammern für ein Komma angegeben.

Summieren aller Gehälter

Das nachfolgende Beispiel zeigt, wie man quasi in einem Einzeiler die Summe der Gehälter aller Mitarbeiter berechnen kann.


 
int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));

Die stream() Methode sorgt dafür, dass die Aggregate-Operation collect einen Stream als Input mit einer Sequenz alle Elemente der Collection bekommt.

Jedes Elemente der Liste ist ein Employee Element. Für den zu ermittelten Gesamtwert der Operation wird die summingInt() Methode von Collectors verwendet. Diese liest für jedes Element, was als Employee-Objekt geliefert wird, über dessen getSalery() das Gehalt des Employee-Objekts aus und fügt es entsprechend zur bisherigen Summe hinzu.

Verändert eine Operation die Daten oder nicht?

Das Collection-Framework hatte bereits vor der Version Java 8 und damit vor der Erweiterung der Stream-API über ein paar sogenannter "Bulk-Operations" verfügt, dh. Operationen, mit deren Hilfe eine gesamte Gruppe von Elementen einer Collection verarbeitet werden konnte.


Die ursprünglich vorhandenen Operationen wie containsAll, addAll oder auch removeAll konnten komplette Collections überarbeiten. Es gibt aber einen ganz entscheidenen Unterschied zwischen den alten Bulk-Operations oder Massen-Operationen auf der einen Seite und den und den neuen mit JAVA 8 über Streams hinzugekommenen Aggregate-Operationen:

Alle alten Bulk-Operationen sind mutative, dh. diese Operationen modifizieren und verändern damit die diesen als Grundlage der Verabeitung von der Collection gelieferten Daten.

Im Gegenzug werden diese Daten der eigentlichen Collection durch die mit Java 8 neu hinzugekommenen Aggregate-Operationen NICHT verändert; zumindest werden diese theoretisch dann nicht verändert, wenn Entwickler bei der Programmierung von Lambda-Expressions darauf achten, solche Veränderungen (engl. Mutations) zu vermeiden.

Insbesondere mit Blick auf parallelStream sollte man dringend darauf achten, dass alle Operationen, die man mit Lambda-Expressions und damit die sogenannte Funktionale Programmierung steuert, auf keinen Fall Nebeneffekte, engl. Side-Effects, haben sollten.

Aggregate-Operationen sollten bevorzugt genutzt werden

Aggregate-Operationen arbeiten wahlweise sequentiell mit Streams oder auch parallel, wenn parallelStream() verwendet wird.

Die Sequenz aller Elemente, die von einer Aggregate-Operation wie mitunter forEach und collect dann zu einem Ergebnis verarbeitet wird, lassen sich auf dem Weg dieser Verarbeitung noch filtern und über map() umwandeln.

Die neuen Aggregate-Operationen verändern NICHT die Original-Collection sondern liefern in Fällen, wo wiederum eine Collection geliefert werden würde, eine neue Collection.

Da die Verwendung von parallelStream letztendlich zu einer nebenläufigen Verarbeitung von Daten über mehrere Prozessoren erfolgt, sind in diesem Fall alle Problemstellungen zu berücksichtigen, die auch im Kontext von Threads zu klären sind. Dieses betrifft mitunter das Problem der Reihenfolge, in welcher Elemente verarbeitet werden, denn bei einer Nebenläufigkeit ist diese Reihenfolge nicht mehr gesichert.

"Traversing Collections" ist der Überbegriff wo wir ursprünglich von einem "Iterieren über Elemente der Collection" haben sprechen können. Wo früher primär mit einem Iterator gearbeitet wurde, bieten die Streams ab Java 8 einen alternativen, neuen, besseren und zu empfehlenden Ansatz.

forEach Konstrukt

Mit Hilfe der forEach-Operation ist es möglich, alle Elemente einer jeden Collection oder übrigens auch einem Array wie in einer for-Schleife zu durchlaufen.

for-Statement für Collections

Syntax: Der erste Wert entspricht dem Element der Collection, welches schrittweise beim Durchlaufen aller Elemente dann für eine Verarbeitung im eigentlichen Körper des for-Statements verarbeitet werden kann.

Der nach dem : folgende Wert ist die Referenz auf ein Objekt vom Typ einer Collection.


 
// Einzeiler
for (Object o : collection) System.out.println(o);

// Zweizeiler
for (Object o : collection) 
 System.out.println(o);

// Dreizeiler
for (Object o : collection) { 
 System.out.println(o);
}

Hinweis: Wenn es sich bei dem für jedes Element durchzuführende Code nur um einen einzigen Ausdruck handelt, können die geschweiften Klammern entfallen. Dieses ermöglicht im Idealfall Code im Einzeiler

Hat man weiterhin nur einen einzigen Ausdruck, kann man auch auf zwei Zeilen umbrechen.

Die Verwendung der geschweiften Klammer bietet den Vorteil, dass Schleifen im Code schneller erkannt werden können. Welchen Effekt das aber in Zeiten funktionaler Programmierung mit Aggregate-Operations noch hat, sei mal dahingestellt.

forEach und for-Loop

Alternativ kann forEach auch direkt verwendet werden, indem wir uns zuerst den Stream für die Collection verschaffen und über die Aggregate-Operation forEach(..) dann angeben, was denn mit jedem einzelnen Element, welches uns dann über den Stream als Sequenz geliefert wird, zu tun ist.


 
collection.stream().forEach(e -> System.out.println(e.toString()));

Collections und Iteratoren

Alle Collections ermöglichen ein Durchlaufen aller Elemente der Gruppe über sogenannte Iteratoren. Iteratoren sind Objekte, welche alle Elemente der Gruppe in irgendeiner Art und Weise quasi durchnumeriert haben und dann über Methoden dieser Iteratoren es ermöglichen, ein Element nach dem anderen zu erhalten.

Iteratoren könnte man vom Prinzip her auch aus Enumeratoren bezeichnen, denn dort, wo man zuvor nur eine von außen zuerst einmal in Bezug auf die interne Ordnung nicht erkennbare Gruppe an Elementen oder quasi Masse von Flöhen hat, stellen Iteratoren sicher, dass wir bei einem Durchlauf alle Elemente geliefert bekommen.

Das Iterator<E> Interface für alle Collection im Java Collection Framework hat die selbe Struktur:


 
public interface Iterator<E> {
 boolean hasNext(); // true wenn noch ein Element kommen wird
 E next(); // Referenz auf nächstes Element
 void remove(); // optionales entfernen bzw. ignorieren
}

Der Iterator merkt sich immer die Position in der Sequenz aller Elemente, die er bereits verarbeitet hat. Will man also vor dem Zugriff auf die next() Methode prüfen, ob überhaupt noch ein weiteres Element geliefert werden kann, wird zuvor hasNext() aufgerufen.

Der einzige verlässliche Ansatz

Wenn man die Gruppe einer Elemente der Collection verlässlich beim Durchlaufen durch das Entferne eines Elements verändern möchte, so ist die Nutzung der remove() Methode des Iterators die EINZIGE VERLÄSSLICHE Variante, das zu tun.

Man ruft zuerst next() auf, um das entsprechende Element zu erhalten, und dann remove(). Die remove() Methode kann also nur das Element entfernen, was zuletzt mit next() geliefert wurde.

Die remove() Methode darf für ein mit next() geliefertes Element auch nur 1x gerufen werden; ein erneuter Aufruf liefert eine Exception.

Wenn bei einem Durchlauf der Elemente der Collection also die remove() Methode aufgerufen wird, so wird nicht nur dieses Elemente bei der weiteren Verarbeitung übersprungen sondern tatsächlich aus der zugrundeliegenden Gruppe aller Elemente der Collection entfernt.


 
static void filter(Collection<?> c) {
 for (Iterator<?> it = c.iterator(); it.hasNext(); )
 if (!checkForRemovement(it.next()))
 it.remove();
}

// Oder
static void filter(Collection<?> c) {
 for (Iterator<?> it = c.iterator(); it.hasNext(); ) {
 if (!checkForRemovement(it.next())) {
 it.remove(); 
 }
 }
}

// Damit das funktionieren kann, muss die Klasse
// über eine statische checkForRemovement(..) Methode
// verfügen welche bei einer Prüfung true oder false liefert.


 /** statische Methode checkForRemovement(..) dieser Klasse.
 static boolean checkForRemovement(Object obj) {
 // Beispiel: Entferne Elemente, die "B" oder "D" sind
 return !obj.equals("B") && !obj.equals("D");
 }


Dieses Beispiel ist «polymorph», des funktioniert also in Java mit jeder Collection.

HINWEIS: Das vollständige Beispiel ist dem Beispiel "Korrektes Entfernen von Elementen mit remove()" zu entnehmen.

Beispiel mit Iterator (Kurzfassung)

Da das Collection Interface das Basis-Interface für alle anderen Interfaces ist, lässt sich ein Iterator für jedes Collection-Objekt, egal welche Interfaces die Implementierungsklasse der Collection noch implementiert hat, über die .iterator() Methode erhalten.


 
import java.util.*;

public class Main {
 public static void main(String[] args) {
 Collection<String> collection = 
 Arrays.asList("Apfel", "Banane", "Kirsche");

 Iterator<String> iterator = collection.iterator();
 
 while (iterator.hasNext()) {
 System.out.println(iterator.next());
 }
 }
}

Arrays.asList(..) ist eine Methode der Arrays-Klasse welchen einen variadischen Parameter beinhaltet, welchem die Anzahl der als Parameter übergebenen Werte egal sind.

Den Iterator erhält man über die iterator() Methode der Collection, über die jede Collection seit Java 8 verfügt.

Die Reihenfolge von while, hasNext, next ist die typische Vorgehensweise, wie man mit Iteratoren arbeitet.

Iterator in Langfassung

Für diejenigen, die ohne Arrays.asList() arbeiten möchten:

Wir können auch direkt eine Collection mit dem Typparameter String zur Speicherung aller Elemente realisieren.


 
import java.util.*;

public class CollectionExample {
 public static void main(String[] args) {
 // Eine Collection mit drei String-Elementen erstellen
 Collection<String> fruits = new ArrayList<>();
 fruits.add("Apfel");
 fruits.add("Banane");
 fruits.add("Kirsche");

 // Iterator zum Durchlaufen der Collection verwenden
 Iterator<String> iterator = fruits.iterator();
 while (iterator.hasNext()) {
 String fruit = iterator.next();
 System.out.println("Frucht: " + fruit);
 }
 }
}


Die Notation verwendet für ArrayList den Diamond-Operator, mit welchem ab Java 8 die Angabe des Typs für den Typparameter fehlen kann, wenn sich dieser ohnehin aus dem Typ der Collection ergibt, in welcher das Objekt gespeichert werden wird.

ConcurrentModificationException

Beim Entfernen von Elementen aus einer Collection während einer Iteration gibt es ein Problem mit der for-each Schleife (for(String item : collection)) oder forEach(), da sie intern einen Iterator verwenden, aber keine direkte Steuerung über remove() erlauben.

Das führt zu einer ConcurrentModificationException, wenn während der Iteration ein Element entfernt wird.

Man sollte deshalb immer, wenn man bei einem Durchlauf von Elementen einer Collection einzelne Elemente entfernen will, NICHT forEach verwenden sondern über einen Iterator der Collection arbeiten.

Der Iterator ist das einzige Objekt, welches beim Durchlauf über alle Elemente der Collection die Kontrolle über diese Collection hat.


 
import java.util.*;

public class FilterExample {


/** main-Methode zum Testen */

 public static void main(String[] args) {
 List<String> items = 
 new ArrayList<>(
 Arrays.asList("A", "B", "C", "D", "E")
 );

 filter(items);

 System.out.println("Gefilterte Liste: " + items);
 }

 /** statische Methode filter(..) dieser Klasse */
 static void filter(Collection<?> c) {
 Iterator<?> it = c.iterator();
 while (it.hasNext()) {
 if (!checkForRemovement(it.next())) {
 // Sicheres Entfernen während der Iteration
 it.remove(); 
 }
 }
 }

 /** statische Methode checkForRemovement(..) dieser Klasse.
 static boolean checkForRemovement(Object obj) {
 // Beispiel: Entferne Elemente, die "B" oder "D" sind
 return !obj.equals("B") && !obj.equals("D");
 }
}

Hinweis: Ein paar der Zeilenumbrüche sind dem Layout dieser Doku geschuldet und hätten vermieden werden können.

Collection Interface Bulk Operations

Die sogenannten Collection Interface Bulk Operations führen Operationen an der gesamten Collection durch. Man kann also als Entwickler diese Operationen dann verwenden, wenn man tatsächlich alle Elemente verarbeiten möchte.

Wie performant und effizient diese Bulk-Operations dann allerdings sind, steht und fällt mit der Problemstellung. Die neuen stream()- und parallelStream()-basierten Varianten können effizienter sein.

returns true if the target Collection contains all of the elements in the specified Collection.

Fügt alle Elemente der als Parameter über gebenen Collection zur target-Collection hinzu.

targetCollection.addAll(parameterCollection);

Entfernt alle Elemente der Collection welche in der als Parameter übergebenen Collection zu finden sind. Damit ist es also möglich, mehrere Elemente auf einmal zu entfernen.

Entfernt alle Elemente von der target-Collectoin, deren Elemente sich nicht in der parameter-Collection befinden.

Die Collection umfasst also am Ende nur noch die Elemente, die als Referenz über die Collection im übergebenen Parameter enthalten waren. Wir bezeichnen das mitunter als "Green-Listing"-Prinzip.

Und weg damit ...

Entfernt alle Elemente der Collection.

Was dann mit diesen passiert im Arbeitsspeicher ist eine Frage der Garbage-Collection der Java Runtime.

Will man alle Elemente, die als Objekt in der Collection enthalten, über removeAll löschen, so ist folgender Ansatz empfehlen:


 
// Alle Person-Elemente einer Collection
// entfernen, welche dem Objekt in e 
// entsprechen. 

Collection<Person> c;
Person e; 
c.removeAll(Collections.singleton(e));

// Alle null-Werte in der Collection entfernen.
c.removeAll(Collections.singleton(null));



// Prinzip, wie man immutable Sets erzeugen kann

import java.util.Collections;
import java.util.Set;

public class FactoryOfImmutableSets {

 // Variante 1
 public static <T> Set<T> createImmutableSet(T element) {
 return Collections.unmodifiableSet(Collections.singleton(element));
 }

 // Variante 2
 public static <T> Set<T> createImmutableSet(Set<T> elements) {
 return Collections.unmodifiableSet(elements);
 }

 public static void main(String[] args) {
 
 Set<String> immutableSet1 = FactoryOfImmutableSets.createImmutableSet("Hallo");
 System.out.println("Immutable Set 1: " + immutableSet1);

 Set<Integer> immutableSet2 = FactoryOfImmutableSets.createImmutableSet(Set.of(1, 2, 3));
 System.out.println("Immutable Set 2: " + immutableSet2);
 }
}


Die statische Methode Collections.singleton(e) liefert ein unveränderliches Set, engl. immutable Set, welches als einziges Objekt das als Parameter e übergebene Objekt beinhaltet.

Collection Interface Array Operations

Mit Hilfe von Collection Interface Array Operations ist es möglich, Collections in Arrays und Arrays in Collections umwandeln zu können. Eine Vielzahl alter Packages arbeitet mit Arrays und noch nicht mit Collections.

Die Elemente einer Collection als Array liefern

Kurz und schmwerzlos:


 
Collection<Object> c = Datenlieferant.getCollection(); 
Object[] a = c.toArray();

Der Array hat eine Größe und liefert damit den length Wert welcher der Anzahl der Elemente in der Collection c entspricht.

Die Elemente einer Collection als Array liefern

Wenn alle Elemente der Collection den selben Typ haben und man dem Array auch gleich den richtigen Typ geben kann, so übergibt man der toArray Methode einen Array von Objekten dieses Typs. Da man diese Objekte zu Beginn nicht hat, ist die Anzahl 0.


 
import java.util.*;

public class Main {
 public static void main(String[] args) {
 Collection<String> c = 
 Arrays.asList("Apfel", "Banane", "Kirsche");
 String[] a = c.toArray(new String[0]);
 
 // Ausgabe: [Apfel, Banane, Kirsche]
 System.out.println(Arrays.toString(a));
 
 
 }
}

Die Methode toArray(T[] a) erwartet ein Array als Parameter, das bestimmt, welchen Typ das Zielarray haben soll. Das Argument new String[0] bedeutet, dass ein leeres Array übergeben wird. Java wird dann automatisch ein neues Array der richtigen Größe erstellen und die Elemente aus c hinein kopieren.

Zusammenfassung

Collection | Zusammenfassung

Links

Quellen, Notes, Tags


    UI ORGANIZED.

    UIO3 Es ist einfacher als Du denkst.

    Stelle noch heute Deine Anfrage.

    uio--WebPageFooter-Module