Elemente aus Java-Sammlungen entfernen

1. Übersicht

In diesem kurzen Tutorial werden vier verschiedene Möglichkeiten zum Entfernen von Elementen aus Java- Sammlungen beschrieben , die bestimmten Prädikaten entsprechen.

Wir werden uns natürlich auch einige der Vorbehalte ansehen.

2. Unsere Sammlung definieren

Zunächst werden zwei Ansätze veranschaulicht, die die ursprüngliche Datenstruktur mutieren. Dann werden wir über zwei andere Optionen sprechen, die anstelle des Entfernens der Elemente eine Kopie der ursprünglichen Sammlung ohne diese erstellen .

Verwenden wir die folgende Sammlung in unseren Beispielen, um zu demonstrieren, wie wir mit verschiedenen Methoden dasselbe Ergebnis erzielen können:

Collection names = new ArrayList(); names.add("John"); names.add("Ana"); names.add("Mary"); names.add("Anthony"); names.add("Mark");

3. Elemente mit Iterator entfernen

Mit dem Iterator von Java können wir jedes einzelne Element in einer Sammlung sowohl durchlaufen als auch entfernen .

Dazu müssen wir zuerst einen Iterator über seine Elemente mit der Iteratormethode abrufen . Anschließend können wir jedes Element mit Hilfe von next aufrufen und mit remove entfernen :

Iterator i = names.iterator(); while(i.hasNext()) { String e = i.next(); if (e.startsWith("A")) { i.remove(); } }

Trotz seiner Einfachheit sollten wir einige Einschränkungen beachten:

  • Abhängig von der Auflistung können ConcurrentModificationException- Ausnahmen auftreten
  • Wir müssen die Elemente durchlaufen, bevor wir sie entfernen können
  • Je nach Sammlung verhält sich remove möglicherweise anders als erwartet. Beispiel: ArrayList.Iterator entfernt das Element aus der Auflistung und verschiebt nachfolgende Daten nach links, während LinkedList.Iterator den Zeiger einfach auf das nächste Element anpasst. Daher ist LinkedList.Iterator beim Entfernen von Elementen wesentlich leistungsfähiger als ArrayList.Iterator

4. Java 8 und Collection.removeIf ()

Java 8 hat eine neue Methode in die Collection- Oberfläche eingeführt, die eine präzisere Möglichkeit zum Entfernen von Elementen mit Predicate bietet :

names.removeIf(e -> e.startsWith("A"));

Es ist wichtig zu beachten, dass removeIf im Gegensatz zum Iterator- Ansatz sowohl in LinkedList als auch in ArrayList eine ähnlich gute Leistung erbringt .

In Java 8 überschreibt ArrayList die Standardimplementierung - die auf Iterator basiert - und implementiert eine andere Strategie: Zunächst werden die Elemente durchlaufen und diejenigen markiert, die unserem Prädikat entsprechen. Anschließend wird ein zweites Mal iteriert, um die Elemente zu entfernen (und zu verschieben), die in der ersten Iteration markiert wurden.

5. Java 8 und die Einführung von Stream

Eine der neuen Hauptfunktionen in Java 8 war das Hinzufügen von Stream (und Collectors ). Es gibt viele Möglichkeiten, einen Stream aus einer Quelle zu erstellen . Bei den meisten Vorgängen, die sich auf die Stream- Instanz auswirken, wird die Quelle jedoch nicht mutiert. Die API konzentriert sich vielmehr darauf, Kopien einer Quelle zu erstellen und alle erforderlichen Vorgänge auszuführen.

Lassen Sie uns einen Blick darauf werfen, wie wir Stream und Collectors verwenden können , um Elemente zu finden / filtern, die mit unserem Prädikat übereinstimmen und nicht übereinstimmen .

5.1. Elemente mit Stream entfernen

Das Entfernen bzw. Filtern von Elementen mithilfe von Stream ist recht einfach . Wir müssen lediglich eine Instanz von Stream mithilfe unserer Sammlung erstellen , den Filter mit unserem Prädikat aufrufen und dann das Ergebnis mithilfe von Collectors erfassen :

Collection filteredCollection = names .stream() .filter(e -> !e.startsWith("A")) .collect(Collectors.toList());

Streaming ist weniger invasiv als die vorherigen Ansätze, fördert die Isolation und ermöglicht die Erstellung mehrerer Kopien aus derselben Quelle. Wir sollten jedoch berücksichtigen, dass dadurch auch der von unserer Anwendung verwendete Speicher erhöht wird.

5.2. Collectors.partitioningBy

Das Kombinieren von Stream.filter und Collectors ist sehr praktisch, obwohl wir möglicherweise auf Szenarien stoßen , in denen wir sowohl übereinstimmende als auch nicht übereinstimmende Elemente benötigen. In solchen Fällen können wir Collectors.partitioning nutzen .

Map
    
      classifiedElements = names .stream() .collect(Collectors.partitioningBy((String e) -> !e.startsWith("A"))); String matching = String.join(",", classifiedElements.get(true)); String nonMatching = String.join(",", classifiedElements.get(false));
    

Diese Methode gibt eine Map zurück , die nur zwei Schlüssel enthält, true und false , die jeweils auf eine Liste verweisen, die die übereinstimmenden bzw. nicht übereinstimmenden Elemente enthält.

6. Fazit

In diesem Artikel haben wir uns einige Methoden zum Entfernen von Elementen aus Sammlungen und einige ihrer Einschränkungen angesehen.

Den vollständigen Quellcode und alle Codefragmente für diesen Artikel finden Sie auf GitHub.