Перейти к основному содержимому

Java ArrayList против вектора

· 4 мин. чтения

1. Обзор

В этом уроке мы сосредоточимся на различиях между классами ArrayList и Vector . Оба они относятся к Java Collections Framework и реализуют интерфейс java.util.List .

Однако эти классы имеют существенные различия в своих реализациях.

2. Что изменилось?

Для начала представим основные отличия ArrayList и Vector. Затем мы обсудим некоторые моменты более подробно:

  • синхронизация — первое существенное различие между этими двумя. Vector синхронизирован, а ArrayList — нет.
  • рост размера. Еще одно различие между ними заключается в том, как они изменяют размер при достижении своей емкости. Вектор удваивает свой размер. Напротив, ArrayList увеличивается только на половину своей длины.
  • итерация — и Vector может использовать Iterator и Enumeration для обхода элементов. С другой стороны, ArrayList может использовать только Iterator .
  • производительность — во многом из-за синхронизации векторные операции выполняются медленнее по сравнению с ArrayList.
  • framework — Кроме того, ArrayList является частью каркаса коллекций и был представлен в JDK 1.2. Между тем, Vector присутствует в более ранних версиях Java как унаследованный класс.

3. Вектор

Поскольку у нас уже есть расширенное руководство по **ArrayList,** мы не будем здесь обсуждать его API и возможности. С другой стороны, мы представим некоторые основные сведения о Vector . ** ``** ``

Проще говоря , вектор представляет собой массив с изменяемым размером . Он может увеличиваться и уменьшаться по мере добавления или удаления элементов.

Мы можем создать вектор обычным способом:

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

Конструктор по умолчанию создает пустой вектор с начальной емкостью 10.

Добавим несколько значений:

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

И, наконец, давайте пройдемся по значениям с помощью интерфейса Iterator :

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

Или мы можем пройти по вектору , используя Enumeration :

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

Теперь давайте более подробно рассмотрим некоторые из их уникальных особенностей.

4. Параллелизм

Мы уже упоминали, что ArrayList и Vector отличаются своей стратегией параллелизма, но давайте рассмотрим ее подробнее. Если бы мы углубились в сигнатуры методов Vector , то увидели бы, что каждая из них имеет ключевое слово synchronized:

public synchronized E get(int index)

Проще говоря, это означает, что только один поток может получить доступ к данному вектору в каждый момент времени .

На самом деле, эта синхронизация на уровне операции в любом случае должна быть наложена на нашу собственную синхронизацию для составных операций.

Напротив, ArrayList использует другой подход. Его методы не синхронизированы, и эта проблема разделена на классы, предназначенные для параллелизма.

Например, мы можем использовать CopyOnWriteArrayList или Collections.synchronizedList , чтобы получить эффект, аналогичный Vector :

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

5. Производительность

Как мы уже говорили выше, Vector синхронизируется, что напрямую влияет на производительность .

Чтобы увидеть разницу в производительности между операциями Vector и ArrayList , давайте напишем простой тест производительности JMH .

В прошлом мы рассматривали временную сложность операций ArrayList , поэтому давайте добавим тестовые примеры для Vector.

Во- первых , давайте протестируем метод get() :

@Benchmark
public Employee testGet(ArrayListBenchmark.MyState state) {
return state.employeeList.get(state.employeeIndex);
}

@Benchmark
public Employee testVectorGet(ArrayListBenchmark.MyState state) {
return state.employeeVector.get(state.employeeIndex);
}

Мы настроим JMH на использование трех потоков и 10 итераций прогрева.

И давайте сообщим среднее время на операцию на уровне наносекунд:

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

Мы видим, что ArrayList#get работает примерно в три раза быстрее, чем Vector#get .

Теперь давайте сравним результаты операции contains() :

@Benchmark
public boolean testContains(ArrayListBenchmark.MyState state) {
return state.employeeList.contains(state.employee);
}

@Benchmark
public boolean testContainsVector(ArrayListBenchmark.MyState state) {
return state.employeeVector.contains(state.employee);
}

И распечатайте результаты:

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

Как мы видим, для операции contains() время выполнения для Vector намного больше, чем для ArrayList .

6. Резюме

В этой статье мы рассмотрели различия между классами Vector и ArrayList в Java. Кроме того, мы также более подробно представили векторные функции.

Как обычно, полный код для этой статьи доступен на GitHub .