Java ArrayList: создание и использование
ArrayList — это удобный динамический массив в Java: легко создавать, менять размер, добавлять, удалять и перебирать элементы. В статье показаны примеры создания, добавления, доступа, замены и удаления элементов, советы о производительности и когда лучше выбрать альтернативы.
Что такое ArrayList

ArrayList — это реализация изменяемого (resizeable) массива в Java из пакета java.util. Он реализует интерфейс List и предоставляет динамическое хранение элементов с индексированным доступом. Коротко:
- Динамическая структура: автоматически меняет внутренний массив при добавлении или удалении элементов.
- Индексированный доступ: поддерживает получение/замену по индексу за константное время в среднем.
- Поддерживает CRUD-операции: add, get, set, remove, indexOf и т.д.
Определение терминов в одну строку:
- List — интерфейс коллекции, где элементы упорядочены и могут иметь дубликаты.
- ArrayList — реализация List на основе изменяемого массива.
Подклассы AbstractList и родственные структуры
AbstractList реализует интерфейс List и даёт основу для структур данных, включая ArrayList. Ближайшие классы и их частые случаи применения:
- LinkedList — эффективная вставка/удаление в середине списка; лучше при частых операциях вставки/удаления по середине.
- Vector — схож с ArrayList, но синхронизирован; используется в многопоточных устаревших приложениях.
- Stack — расширяет Vector, реализует LIFO-стек; чаще заменяется Deque/ArrayDeque.
Эти классы затрагиваются лишь поверхностно: фокус статьи — базовая работа с ArrayList.
Создание ArrayList
Создание пустого ArrayList требует импорта:
import java.util.ArrayList;Пустой ArrayList через конструктор без аргументов:
ArrayList alist = new ArrayList(); Указание начальной ёмкости (hint для выделения памяти):
ArrayList alist = new ArrayList(8); Внутренне это выделяет массив на указанное количество индексов, но ArrayList автоматически расширится при необходимости, поэтому ёмкость — это подсказка для возможного увеличения производительности.
Заполнение ArrayList
Добавление в конец
Добавление одного элемента в конец выполняется через add():
ArrayList alist = new ArrayList();
alist.add("apple");
alist.add("banana");
alist.add("cantaloupe");
alist.add("orange");
System.out.println(alist); Вывод в консоль:
[apple, banana, cantaloupe, orange]Метод size() возвращает текущее количество элементов:
System.out.println("Number of elements in the arraylist: " + alist.size());Добавление в заданный индекс
Чтобы вставить элемент в конкретную позицию, передайте индекс и элемент:
alist.add(3, "grapes");
System.out.println(alist);Результат:
[apple, banana, cantaloupe, grapes, orange]Напоминание: индексы в Java начинаются с нуля.
Добавление коллекции целиком
Можно добавить все элементы из другой коллекции с помощью addAll():
List items = Arrays.asList("pear", "cherry");
alist.addAll(items);
System.out.println(alist);
// [apple, banana, cantaloupe, grapes, orange, pear, cherry] Также есть перегрузка addAll(int index, Collection) для вставки коллекции в указанную позицию.
Доступ к элементам
Получение по индексу
Если индекс известен, используйте get(index):
String item = alist.get(2);
System.out.println("Item at index 2 is: " + item);
// Item at index 2 is: cantaloupeПоиск индекса элемента
Если индекс неизвестен, indexOf(element) вернёт позицию или -1, если элемент не найден:
System.out.println(alist);
int index = alist.indexOf("orange");
if (index < 0) {
System.out.println("Item \"orange\" not found");
} else {
System.out.println("Item \"orange\" found at index " + index);
}Если элемент отсутствует:
index = alist.indexOf("grape");
if (index < 0) {
System.out.println("Item \"grape\" not found");
}
// Item "grape" not foundИтерация по ArrayList
Частая задача — пройтись по всем элементам.
- Расширенный for-loop (рекомендуется для простого чтения):
for (String fruit : alist) {
System.out.println("Found fruit \"" + fruit + "\"");
}- Iterator — нужен, если требуется безопасное удаление во время обхода:
ArrayList blist = new ArrayList(alist);
for (Iterator iter = blist.iterator() ; iter.hasNext() ; ) {
String fruit = iter.next();
if (fruit.startsWith("c")) {
iter.remove();
} else {
System.out.println("Keeping \"" + fruit + "\"");
}
} Iterator.remove() безопасно удаляет текущий элемент итерации и предотвращает ConcurrentModificationException.
Замена элементов
Метод set(index, element) заменяет значение по индексу:
alist.set(5, "pineapple");
System.out.println(alist);
// [apple, banana, cantaloupe, grapes, orange, pineapple, cherry]Удаление элементов
remove(index) удаляет по индексу и возвращает удалённый элемент:
String fruit = alist.remove(2);
System.out.println("Removed element at 2: " + fruit);
// Removed element at 2: cantalouperemove(Object) удаляет первое вхождение элемента и возвращает boolean:
fruit = "grapes";
System.out.println("Remove " + fruit + " from the list? " + alist.remove(fruit));
// Remove grapes from the list? trueКогда ArrayList подходит, а когда нет
Когда выбрать ArrayList:
- Частые операции чтения и произвольный доступ по индексу.
- Добавление в конец списка (амортизированное O(1)).
- Когда необходим упорядоченный список с возможными дубликатами.
Когда не выбирать ArrayList:
- Много вставок/удалений в середине списка — лучше LinkedList.
- Нужна уникальная пара (ключ->значение) — лучше HashMap.
- Высокая конкуренция потоков и требуется синхронизация — рассмотрите Concurrent collections или Vector только при совместимости с устаревшим кодом.
Альтернативы и сравнение (кратко)
- LinkedList — лучше для частых вставок/удалений в середине; операции get(i) — O(n).
- HashMap — хранение по ключу; быстрый доступ по ключу, порядок не гарантируется (используйте LinkedHashMap для упорядоченности).
- ArrayDeque — более эффективный стек/очередь, чем Stack/Vector.
Модель мышления и эвристики при выборе
- Если доступ по индексу и быстрые чтения важнее — ArrayList.
- Если вставки/удаления посреди частые — LinkedList или специализированная структура.
- Если ключ — это уникальный идентификатор, используйте Map.
Правило большого пальца: оптимизируйте под наиболее частую операцию (чтение vs вставка/удаление).
Быстрый справочник (cheat sheet)
- Создать: new ArrayList<Тип>();
- Добавить: add(element), add(index, element)
- Добавить коллекцию: addAll(collection), addAll(index, collection)
- Получить: get(index)
- Найти: indexOf(element)
- Заменить: set(index, element)
- Удалить: remove(index) или remove(object)
- Размер: size()
- Очистить: clear()
Ролевые чек-листы
Для разработчика:
- Проверить: нужен ли упорядоченный список или Map.
- Указать тип (generics) для безопасности типов.
- Задать начальную ёмкость, если известен ожидаемый размер.
- Использовать Iterator.remove при удалении во время итерации.
Для ревьюера кода:
- Убедиться, что операции не выполняют лишних копирований коллекций.
- Проверить границы индексов и обработку исключений.
- Оценить многопоточность: нужен ли synchronized/ConcurrentList.
Для архитектора:
- Оценить нагрузку: частые вставки в середину vs чтения.
- Выбрать структуру в зависимости от требований по производительности и памяти.
Фактбокс с ключевыми моментами
- ArrayList реализует List и основан на массиве.
- get(index) — O(1) в среднем; вставка в конец — амортизированное O(1).
- Вставка/удаление в середине — O(n).
- indexOf — O(n).
Примеры неисправностей и когда подход ломается
- ConcurrentModificationException: попытка модифицировать коллекцию вне Iterator во время итерации.
- Падение производительности при частых вставках в середину: в этом случае LinkedList или специализированная структура окажутся быстрее.
- Утечки памяти при хранении большого количества объектов: стоит рассмотреть хранение ссылок на объекты меньшего размера или потоковую обработку.
Небольшая методология миграции с ArrayList на альтернативы
- Замерить: профилируйте приложение и подтвердите узкие места.
- Проанализировать паттерн доступа: чтение/запись/удаление.
- Прототип: заменить ArrayList на LinkedList/Map/Deque в тестовом модуле.
- Тесты: убедиться в отсутствии регрессий и сохранении API.
- Внедрение постепенно, мониторинг метрик.
Простой алгоритм выбора (Mermaid)
flowchart TD
A[Нужен упорядоченный список?] -->|Нет| B[Используйте Map 'HashMap/LinkedHashMap']
A -->|Да| C[Частые вставки/удаления в середине?]
C -->|Да| D[LinkedList]
C -->|Нет| E[ArrayList]
E --> F{Многопоточный доступ?}
F -->|Да| G[Используйте Concurrent коллекции или синхронизацию]
F -->|Нет| H[ArrayList — подходит]Критерии приёмки
- unit-тесты покрывают операции add/get/set/remove и проверки границ индексов.
- нет ConcurrentModificationException в многопоточной среде (или используется безопасная стратегия).
- производительность укладывается в требования нагрузки (латентность/пропускная способность).
Итог и рекомендации
ArrayList — мощный и часто используемый инструмент для большинства задач, связанных с упорядоченными коллекциями в Java. Он хорош для быстрого доступа по индексу и эффективного добавления в конец. Тем не менее, важно выбирать структуру данных под рабочие сценарии: при частых вставках в середине или при хранении по ключу рассмотрите LinkedList или Map.
Важно
- Всегда указывайте дженерики (например, ArrayList
), чтобы избежать непредвиденных ClassCastException. - При удалении во время итерации используйте Iterator.remove().
Краткое резюме
ArrayList — базовый инструмент коллекций Java: прост в использовании, гибок и эффективен для чтения и добавления в конец. Для других шаблонов доступа выбирайте соответствующие структуры.
Похожие материалы
Как сделать слайдер для камеры за $35
Как стримить с телефона на ПК через OBS
Как удалить аккаунт Reddit — полное руководство
Как выбрать камеру для влогинга
Как сравнить процессоры CPU: практическое руководство