Начальный размер для ArrayList


257

Вы можете установить начальный размер для ArrayList, выполнив

ArrayList<Integer> arr=new ArrayList<Integer>(10);

Тем не менее, вы не можете сделать

arr.add(5, 10);

потому что это вызывает исключение вне границ.

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

Функция добавления определена add(int index, Object element)так, что я не добавляю к индексу 10.


52
На самом деле, его не видно из документации , что список должен иметь по меньшей мере п элементов добавляется , прежде чем вы можете set/addпункт п-1 .
Восприятие

5
Восприятие: я не знаю, если это очевидно, но это уточняется. Необходимо внимательно прочитать JavaDoc. Throws: IndexOutOfBoundsException - если индекс выходит за пределы диапазона (index <0 || index> = size ()).
Natix

3
Хм, конструктор говорит: «Создает пустой список с указанной начальной емкостью.», Принимая понятие пустого списка, не может быть индекса 5. Но я согласен, что это может быть не видно на первый взгляд ...
quaylar

12
Я думаю также справедливо сказать, что если вы инициализируете массив определенным значением, вы будете предполагать, что индексы ниже этого значения доступны - и это так ArrayList. Я лично хотел бы метод, который позволил бы мне установить размер так, чтобы я мог поместить вещи в определенные индексы. Этот метод явно отсутствует.
Эндрю Уайлд

1
Какой numbskull разработал коллекции таким образом ?! Это вызывает избыточную работу для параллельной реализации структуры с элементами переменной длины (т. Е. ArrayList <String []>, где каждый массив может иметь различную длину). Если память уже распределена, поэтому список не нуждается в перераспределении после добавления N элементов, эти индексы должны быть непосредственно доступны с самого начала. Никто в Oracle не изучал этот шаблон после C / C ++, C #, Objective C и Swift ?!
patrickjp93

Ответы:


387

Вы путаете размер списка массивов с его емкостью:

  • размер является количество элементов в списке;
  • емкость , сколько элементов списка потенциально может вместить без перераспределить свои внутренние структуры.

Когда вы звоните new ArrayList<Integer>(10), вы устанавливаете начальную емкость списка , а не его размер. Другими словами, при построении таким образом список массивов начинает свою жизнь пустым.

Один из способов добавить десять элементов в список массивов - использовать цикл:

for (int i = 0; i < 10; i++) {
  arr.add(0);
}

Сделав это, вы теперь можете изменять элементы с индексами 0..9.


51
+1: более короткий цикл. while(arr.size() < 10) arr.add(0);Можно сказать, что размер должен быть не меньше 10. Например, вы можете использоватьarr.set(9, n);
Питер Лоури

10
+1: Отличный ответ, я бы дал +10, если бы мог. Из API не сразу видно, почему вы не можете установить ОБА начальный размер и начальную емкость в одном вызове конструктора. Вы как бы должны прочитать API и сказать: «О, я думаю, у ArrayList нет метода или конструктора, чтобы сделать это»
demongolem

@PeterLawrey Ваш код может быть короче, но содержит два вызова метода на одну итерацию цикла, а не один.
невралмер

@neuralmer Я бы ожидал, что size () и add () будут встроены, поэтому во время выполнения не будет никакого реального вызова метода.
Питер Лори

109

Если вы хотите список с предопределенным размером, вы также можете использовать:

List<Integer> arr = Arrays.asList(new Integer[10]);

11
Небольшой недостаток здесь, результат Listполон нулей. С Guava мы можем сделать, Ints.asList(new int[10])что будет инициализировать наш список с 0s. Чистый образец, хотя, спасибо за пример.
dimo414

1
Вопросы говорят о ArrayList <E>. Вы используете Список <E>. Никто не заметил это ??? Более того, они проголосовали за этот неуместный ответ! Я не понижаю ваш ответ, потому что никогда не делаю. Просто ... Боже мой!
Апостол

3
@Apostolos ArrayListявляется реализацией Listинтерфейса и Arrays.asListвозвращает ArrayList. Я предлагаю вам посмотреть полиморфизм.
Лиам Поттер

Это возвращает список с фиксированным размером, хотя. Попытка добавить больше элементов бросковUnsupportedOperationException
Корай Тугай

47

если вы хотите использовать Collections.fill (list, obj); для того, чтобы заполнить список повторяющимся объектом, вы можете использовать

ArrayList<Integer> arr=new ArrayList<Integer>(Collections.nCopies(10, 0));

строка копирует 10 раз 0 в ваш ArrayList


20

Емкость из ArrayListне то же самое , как ее размер . Размер равен количеству элементов, содержащихся в ArrayList(и любой другой Listреализации).

Мощности просто длина основного массива , который используется для хранения internaly элементов ArrayList, и всегда больше или равен размеру списка.

При вызове set(index, element)списка indexотносится к фактическому количеству элементов списка (= размер) (который равен нулю в вашем коде, поэтому AIOOBEвыбрасывается), а не к длине массива (= емкость) (которая зависит от деталей реализации к ArrayList).

Этот setметод является общим для всех Listреализаций, например LinkedList, который на самом деле не реализуется массивом, а представляет собой связанную цепочку записей.

Изменить : Вы на самом деле используете add(index, element)метод set(index, element), но принцип здесь тот же.


10

Если вы хотите добавить элементы с индексом, вы можете вместо этого использовать массив.

    String [] test = new String[length];
    test[0] = "add";

5
ОП хотел изначально использовать список ... а не массив.
Стефан

9

10 - начальная емкость AL, а не размер (который равен 0). Вы должны упомянуть начальную емкость до некоторого высокого значения, когда у вас будет много элементов, потому что это позволяет избежать накладных расходов на расширение емкости, поскольку вы продолжаете добавлять элементы.


6

Я думаю, что точный ответ на ваш вопрос будет:

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



3

Опоздав на это, но после Java 8 я лично считаю следующий подход с StreamAPI более лаконичным и может быть альтернативой принятому ответу .

Например,

Arrays.stream(new int[size]).boxed().collect(Collectors.toList())

где sizeжелаемый Listразмер и без недостатка, упомянутого здесь , все элементы в Listинициализируются как 0.

(Я сделал быстрый поиск и не увидел streamни одного опубликованного ответа - не стесняйтесь, дайте мне знать, если этот ответ является избыточным, и я могу удалить его)


1

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

Просто позвони:

arr.add(10)

добавить Integer в ваш ArrayList


1

Хотя ваш массив имеет емкость 10, настоящий список не содержит здесь элементов. Метод add используется для вставки элемента в реальный список. Поскольку он не имеет элементов, вы не можете вставить элемент в индекс 5.


1

Если вы хотите добавить 10 элементов к себе, ArrayListвы можете попробовать это:

for (int i = 0; i < 10; i++)
    arr.add(i);

Если вы уже объявили переменную размера массива, вы бы использовали переменную sizeвместо числа «10»


1

Я столкнулся с подобной проблемой, и просто зная, что arrayList является реализацией изменяемого размера массива интерфейса List, я также ожидаю, что вы можете добавить элемент в любую точку, но, по крайней мере, иметь возможность определить начальный размер. В любом случае, вы можете сначала создать массив и преобразовать его в список, например:

  int index = 5;
  int size = 10;

  Integer[] array = new Integer[size];
  array[index] = value;
  ...
  List<Integer> list = Arrays.asList(array);

или

  List<Integer> list = Arrays.asList(new Integer[size]);
  list.set(index, value);

0

ArrayList myList = new ArrayList (10);

//  myList.add(3, "DDD");
//  myList.add(9, "III");
    myList.add(0, "AAA");
    myList.add(1, "BBB");

    for(String item:myList){
        System.out.println("inside list : "+item);
    }

/ * Заявить, что первоначальный потенциал arraylist - это не что иное, как экономия времени на внутреннюю перестановку; когда мы добавляем элемент внутренне, он проверяет емкость, чтобы увеличить емкость, вы можете добавить элемент с индексом 0 изначально, затем 1 и так далее. * /


0

Мои два цента на Stream. Я думаю, что лучше использовать

IntStream.generate(i -> MyClass.contruct())
         .limit(INT_SIZE)
         .collect(Collectors.toList());

с гибкостью, чтобы поставить любые начальные значения.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.