В программировании на Java массивы и списки массивов — две фундаментальные структуры данных, часто используемые для хранения коллекций элементов. Хотя обе используются для одних и тех же целей, их отличительные характеристики существенно влияют на производительность и гибкость приложения.
В этом руководстве по Java рассматриваются важные особенности массивов и списков массивов, их сильные и слабые стороны, а также различные методы преобразования между этими двумя структурами, обеспечивающие плавные переходы при необходимости.
1. Введение
В Java ArrayList является частью фреймворка коллекции и реализации структуры данных изменяемого размера массива. Это означает, что arraylist внутри себя поддерживает массив, который динамически увеличивается или уменьшается по мере необходимости.
1.1 Массивы Java
Массив — это структура данных фиксированного размера, которая хранит элементы одного типа данных в непрерывной ячейке памяти. Каждый элемент в массиве идентифицируется индексом или позицией, начиная с 0 для первого элемента.
Массивы в Java такие же, как и в других языках программирования. Обычно массивы имеют следующие особенности:
- Массивы всегда хранят элементы одного и того же типа данных. Тип массива объявляется во время инициализации.
- Массив целых чисел может хранить только целые значения. Компилятор Java не позволит хранить строки в этом целочисленном массиве.
- Доступ к каждому элементу массива осуществляется только с помощью индекса. Другого способа доступа к элементам массива нет.
- Размер массива всегда фиксирован и не может быть изменен. Чтобы сохранить больше элементов, чем размер массива, мы должны создать новый массив и скопировать элементы из старого массива в новый. Когда мы пытаемся добавить больше, чем его размер, он выдает ArrayIndexOutOfBoundsException.
Например, внутреннее представление памяти следующего массива выглядит следующим образом:
int[] a = new int[5];a[0] = 1;a[1] = 2;a[2] = 4;a[3] = 8;a[4] = 16;

Массивы имеют фиксированный размер, что означает, что после создания массива его размер не может быть изменен. Доступ к каждому элементу массива осуществляется с использованием соответствующего индекса.
for(int i = 0; i < a.length; i++) {System.out.println(a[i]);}
1.2.Java ArrayList
Класс ArrayList является частью фреймворка коллекций Java и реализует интерфейс List. В отличие от массивов, ArrayList может динамически увеличиваться или уменьшаться по мере добавления или удаления элементов.
Можно хранить элементы нескольких типов в arraylist, но чаще всего это не рекомендуется, так как это может вызвать ClassCastException во время выполнения, когда мы извлекаем элементы из массива. Для обеспечения безопасности типов используются обобщения для объявления типов элементов, хранящихся в arraylist.
List<Integer> arraylist = new ArrayList<>();arraylist.add(1); // allowed//arraylist.add("one"); // NOT allowed
Помимо последовательного доступа с использованием цикла for, arraylists позволяют перебирать элементы с использованием итераторов, таких как ListIterator. Когда мы используем итераторы и изменяем коллекцию с помощью итераторов, это не происходит через ConcurrentModificationException.
List<Integer> arraylist = new ArrayList<>();arraylist.add(1);arraylist.add(2);arraylist.add(3);//1 - using foreach looparraylist.forEach(System.out::println);//2 - using iteratorListIterator<Integer> listIterator = arraylist.listIterator();while(listIterator.hasNext()) {System.out.println(listIterator.next());}
2. Различия между Array и ArrayList в Java
В следующей таблице суммировано сравнение массивов и arraylists. Она сравнивает обе структуры данных на основе их производительности, простоты использования и вариантов использования.
Особенность | Массивы | ArrayLists |
---|---|---|
Фиксированный размер против динамического изменения размера | Выделяется с фиксированным размером во время инициализации | Динамическое изменение размера при добавлении или удалении элементов. |
Управление памятью и эффективность | Фиксированный размер может привести к неэффективному использованию памяти, если размер массива превышает фактическое количество содержащихся в нем элементов. | Динамическое изменение размера приводит к небольшому снижению производительности за счет оптимизированного использования памяти. |
Синтаксис и простота использования | Прямой синтаксис для операций инициализации, добавления, удаления и обновления. | Более интуитивный и удобный способ работы с методами API коллекций. |
Производительность | Для операций чтения/записи массивы, как правило, работают быстрее благодаря прямому доступу к элементам с использованием индексов. Для операций записи, где требуется изменение размера, списки массивов могут превзойти массивы. | За исключением операций записи, требующих изменения размера, ArrayList работает хуже, чем массивы. |
Лучше всего использовать для | Используйте массивы, когда требуется коллекция фиксированного размера, а эффективность использования памяти имеет решающее значение. | ArrayList лучше всего использовать для небольших коллекций, где удобство важнее небольшого и незначительного прироста производительности. |
3. Преобразовать массив в ArrayList
Самый простой способ преобразовать массив в ArrayList — использовать метод Arrays.asList(), который создает представление List массива, а затем мы создаем новый ArrayList с помощью конструктора ArrayList. Это фактически преобразует массив в ArrayList.
String[] array = {"apple", "banana", "cherry"};ArrayList<String> arrayList = new ArrayList<>(Arrays.asList(array));
В качестве альтернативы мы также можем использовать потоки Java 8 для итерации по элементам массива и сбора их в новый ArrayList. Это дает нам возможность выполнить дополнительные операции над каждым элементом массива перед сбором их в список.
ArrayList<String> arrayList = Arrays.stream(array)//additional actions.collect(Collectors.toCollection(ArrayList::new));
4. Преобразовать ArrayList в массив
Простейшим решением для преобразования arraylist в массив является использование метода ArrayList.toArray(), который содержит все элементы списка в правильной последовательности. ToArray() возвращает массив типа Object[], поэтому вам необходимо указать тип нужного массива в качестве аргумента для метода toArray().
Размер нового массива определяется размером ArrayList.
ArrayList<String> arrayList = new ArrayList<>();arrayList.add("apple");arrayList.add("banana");arrayList.add("cherry");String[] array = arrayList.toArray(new String[arrayList.size()]);
5. Лучшие практики и рекомендации
Оба, ArrayLists и массивы, служат почти одинаковым целям и имеют свои собственные преимущества друг перед другом. Следующие рекомендации должны помочь нам сузить и выбрать правильную структуру данных для нашего приложения.
5.1 Частота операций по изменению размера
Если изменение размера массива требуется часто из-за особых требований, рекомендуется использовать ArrayList. Внутренняя обработка операций изменения размера устраняет сложность кода приложения и обеспечивает почти такой же прирост производительности, как и при выполнении вручную.
5.2. Квалифицируемые улучшения производительности
Если прирост производительности не значительно выше, то всегда рекомендуется выбирать arraylists вместо arrays. ArrayLists устраняют сложность и делают код более читаемым, а также обеспечивают почти аналогичную производительность для небольших коллекций.
Лучший способ оценить прирост производительности — это измерить его с помощью любого инструмента, например JMH.
5.3 Примитивы против объектов-оболочек
Массивы могут напрямую работать с примитивными типами, тогда как arraylists работают с объектами, т.е. классом-оболочкой в данном случае. Если в приложении требуется постоянное преобразование между обоими типами при их обработке, лучше всего использовать массивы, поскольку они упростят код, убрав ненужное приведение типов, и за счет этого дадут небольшой прирост производительности.
int[] array = new int[10];//Creating arraylist for 'int' type is not possible. We must create arraylist of type 'Integer'ArrayList<Integer> arraylist = new ArrayList<>();
5.4 Взаимодействие с другими типами коллекций
ArrayList является частью фреймворков коллекций Java и, таким образом, без проблем работает с другими типами, такими как Map, Set и т. д. Использование массивов приведет к ненужным и дополнительным шагам для преобразования между другими типами коллекций.
Использование ArrayList сократит количество таких преобразований и, таким образом, создаст более читабельный и лаконичный код.
6. Заключение
В заключение следует отметить, что в передовых практиках разработки на Java чаще всего рекомендуется использовать ArrayLists и другие встроенные классы коллекций из-за их гибкости, простоты использования и схожей производительности для коллекций малого и среднего размера.
Однако есть случаи, когда массивы могут быть более подходящими, особенно когда производительность или эффективность использования памяти являются первостепенными задачами.