Java ArrayList vs Vector

Übersicht

In diesem Tutorial konzentrieren wir uns auf die Unterschiede zwischen den Klassen ArrayList und Vector. Beide gehören zum Java Collections Framework und implementieren Java.util.Liste Schnittstelle.

Diese Klassen weisen jedoch signifikante Unterschiede in ihren Implementierungen auf.

Was ist anders?

Lassen Sie uns zunächst die Hauptunterschiede von ArrayList und Vector . Dann werden wir einige der Punkte genauer besprechen:

  • Synchronisation – Der erste große Unterschied zwischen diesen beiden. Vektor ist synchronisiert und ArrayList nicht.
  • Größenwachstum – Ein weiterer Unterschied zwischen den beiden ist die Art und Weise, wie sie die Größe ändern, während sie ihre Kapazität erreichen. Der Vektor verdoppelt seine Größe. Im Gegensatz dazu erhöht sich ArrayList nur um die Hälfte seiner Länge
  • Iteration – Und Vector kann Iterator und Enumeration verwenden, um die Elemente zu durchlaufen. Auf der anderen Seite kann ArrayList nur Iterator verwenden.
  • Leistung – Hauptsächlich aufgrund der Synchronisation sind Vektoroperationen im Vergleich zu ArrayList langsamer
  • Framework – Außerdem ist ArrayList Teil des Collections-Frameworks und wurde in JDK 1.2 eingeführt. Inzwischen ist Vector in den früheren Versionen von Java als Legacy-Klasse vorhanden.

Vector

Da wir bereits eine erweiterte Anleitung zu ArrayList haben, werden wir hier nicht auf die API und die Funktionen eingehen. Auf der anderen Seite werden wir einige Kerndetails zu Vector vorstellen.

Einfach ausgedrückt ist ein Vektor ein veränderbares Array. Es kann wachsen und schrumpfen, wenn wir die Elemente hinzufügen oder entfernen.

Wir können einen Vektor in typischer Weise erstellen:

Vector<String> vector = new Vector<>();

Der Standardkonstruktor erstellt einen leeren Vektor mit einer Anfangskapazität von 10.

Fügen wir ein paar Werte hinzu:

vector.add("baeldung");vector.add("Vector");vector.add("example");

Und schließlich iterieren wir die Werte mithilfe der Iterator-Schnittstelle:

Iterator<String> iterator = vector.iterator();while (iterator.hasNext()) { String element = iterator.next(); // ...}

Oder wir können den Vektor mit Enumeration durchlaufen:

Enumeration e = vector.elements();while(e.hasMoreElements()) { String element = e.nextElement(); // ... }

Lassen Sie uns nun einige ihrer einzigartigen Funktionen genauer untersuchen.

Parallelität

Wir haben bereits erwähnt, dass ArrayList und Vector sich in ihrer Parallelitätsstrategie unterscheiden, aber schauen wir uns das genauer an. Wenn wir in die Methodensignaturen von Vector eintauchen würden, würden wir sehen, dass jeder das synchronized Schlüsselwort hat:

public synchronized E get(int index)

Einfach ausgedrückt bedeutet dies, dass jeweils nur ein Thread auf einen bestimmten Vektor zugreifen kann.

Wirklich, diese Synchronisationen auf Operationsebene müssen jedoch sowieso mit unserer eigenen Synchronisation für zusammengesetzte Operationen überlagert werden.

Im Gegensatz dazu verfolgt ArrayList einen anderen Ansatz. Seine Methoden sind nicht synchronisiert und dieses Problem ist in Klassen unterteilt, die der Parallelität gewidmet sind.

Zum Beispiel können wir CopyOnWriteArrayList oder Collections verwenden.synchronizedList, um einen ähnlichen Effekt wie Vektor zu erhalten:

vector.get(1); // synchronizedCollections.synchronizedList(arrayList).get(1); // also synchronized

Leistung

Wie bereits oben erwähnt, wird der Vektor synchronisiert, was sich direkt auf die Leistung auswirkt.

Um den Leistungsunterschied zwischen Vektor- und ArrayList-Operationen zu sehen, schreiben wir einen einfachen JMH-Benchmark-Test.

In der Vergangenheit haben wir uns die Zeitkomplexität der Operationen von ArrayList angesehen, also fügen wir die Testfälle für Vector hinzu.

Testen wir zuerst die get() -Methode:

@Benchmarkpublic Employee testGet(ArrayListBenchmark.MyState state) { return state.employeeList.get(state.employeeIndex);}@Benchmarkpublic Employee testVectorGet(ArrayListBenchmark.MyState state) { return state.employeeVector.get(state.employeeIndex);}

Wir konfigurieren JMH so, dass drei Threads und 10 Warmup-Iterationen verwendet werden.

Und lassen Sie uns über die durchschnittliche Zeit pro Operation auf Nanosekundenebene berichten:

Benchmark Mode Cnt Score Error UnitsArrayListBenchmark.testGet avgt 20 9.786 ± 1.358 ns/opArrayListBenchmark.testVectorGet avgt 20 37.074 ± 3.469 ns/op

Wir können sehen, dass ArrayList#get etwa dreimal schneller funktioniert als Vector#get .

Vergleichen wir nun die Ergebnisse der Operation contains():

@Benchmarkpublic boolean testContains(ArrayListBenchmark.MyState state) { return state.employeeList.contains(state.employee);}@Benchmarkpublic boolean testContainsVector(ArrayListBenchmark.MyState state) { return state.employeeVector.contains(state.employee);}

Und drucken Sie die Ergebnisse aus:

Benchmark Mode Cnt Score Error UnitsArrayListBenchmark.testContains avgt 20 8.665 ± 1.159 ns/opArrayListBenchmark.testContainsVector avgt 20 36.513 ± 1.266 ns/op

Wie wir sehen können, ist die Leistungszeit für Vector für die Operation contains() viel länger als für ArrayList .

Zusammenfassung

In diesem Artikel haben wir uns die Unterschiede zwischen den Klassen Vector und ArrayList in Java angesehen. Darüber hinaus haben wir die Vektorfunktionen detaillierter vorgestellt.

Wie üblich ist der vollständige Code für diesen Artikel auf GitHub verfügbar.

Erste Schritte mit Spring 5 und Spring Boot 2 über den Learn Spring-Kurs:

>> SCHAUEN SIE SICH DEN KURS AN



+