List.clear() vs list = new ArrayList <Integer>();

Какой из двух вариантов лучше и быстрее очистить ArrayList и почему?

list.clear() 

или

list = new ArrayList<Integer>();

Бывает, что я должен в случайные моменты очистить все записи из моего ArrayList, и у меня нет способа узнать, сколько новых записей будет в будущем, может быть 0 или 1000. Какой метод быстрее и лучше, и почему?

Ответ 1

Трудно знать без теста, но если у вас много элементов в ArrayList, а средний размер ниже, возможно, быстрее создать новый ArrayList.

http://www.docjar.com/html/api/java/util/ArrayList.java.html

public void clear() {
    modCount++;

    // Let gc do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

Ответ 2

List.clear удалит элементы, не уменьшая емкость списка.

groovy:000> mylist = [1,2,3,4,5,6,7,8,9,10,11,12]
===> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
groovy:000> mylist.elementData.length
===> 12
groovy:000> mylist.elementData
===> [Ljava.lang.Object;@19d6af
groovy:000> mylist.clear()
===> null
groovy:000> mylist.elementData.length
===> 12
groovy:000> mylist.elementData
===> [Ljava.lang.Object;@19d6af
groovy:000> mylist = new ArrayList();
===> []
groovy:000> mylist.elementData
===> [Ljava.lang.Object;@2bfdff
groovy:000> mylist.elementData.length
===> 10

Здесь mylist очищается, ссылки на элементы, принадлежащие ему, отключаются, но он сохраняет один и тот же массив поддержки. Затем mylist был повторно инициализирован и получил новый массив поддержки, старый получил GCed. Таким образом, один из способов удерживается в памяти, а другой выдает свою память и перераспределяется с нуля (с установленной по умолчанию мощностью). Это лучше зависит от того, хотите ли вы уменьшить отбраковку мусора или свести к минимуму текущее количество неиспользуемой памяти. Может ли список придерживаться достаточно долго, чтобы быть перемещенным из Эдема, может быть фактором, определяющим, что быстрее (потому что это может сделать сбор мусора более дорогим).

Ответ 3

Я думаю, что ответ заключается в том, что это зависит от целого ряда факторов, таких как:

  • можно ли заранее спрогнозировать размер списка (т.е. можете ли вы точно установить емкость),
  • является ли размер списка переменным (т.е. каждый раз, когда он заполняется),
  • как долго будет длиться время существования списка в обеих версиях, и
  • ваши параметры кучи /GC и процессор.

Это затрудняет прогнозирование того, что будет лучше. Но моя интуиция заключается в том, что разница не будет такой большой.

Два совета по оптимизации:

  • Не тратьте время, пытаясь оптимизировать это... если приложение не является объективно слишком медленно и измерение с помощью профилировщика говорит вам, что это горячая точка производительности. (Скорее всего, одно из этих предварительных условий не будет выполнено.)

  • Если вы решили оптимизировать это, сделайте это с научной точки зрения. Попробуйте обе (все) альтернативы и определите, какая из них лучше, измерив производительность в вашем реальном приложении на реалистичной задаче/рабочей нагрузке/входном наборе. (Искусственный тест может дать вам ответы, которые не предсказывают поведение в реальном мире из-за факторов, подобных тем, которые я перечислил ранее.)

Ответ 4

Первый .clear(); сохранит тот же список, который просто очистит список.

Второй new ArrayList<Integer>(); создает новый ArrayList в памяти.

Предложение: Первое, потому что это то, что предназначено для выполнения.

Ответ 5

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

Ответ 6

Пробовал программу ниже, используя оба подхода. 1. С очисткой arraylist obj in for loop 2. Создание нового цикла New Arraylist in for.

List al= new ArrayList();
        for(int i=0;i<100;i++)
        {
            //List al= new ArrayList();

            for(int j=0;j<10;j++)
            {
                al.add(Integer.parseInt("" +j+i));
                //System.out.println("Obj val " +al.get(j));
            }
            //System.out.println("Hashcode : " + al.hashCode());
            al.clear();

        }

и к моему удивлению. распределение памяти не сильно изменилось.

С новым подходом к Arraylist.

До полной свободной памяти: 64,909::

Полная свободная память цикла: 64,775::

с четким подходом,

Перед циклом полная свободная память: 64,909:: После цикла полная свободная память: 64,765::

Итак, это говорит о том, что нет большой разницы в использовании arraylist.clear с точки зрения использования памяти.

Ответ 7

list.clear() будет поддерживать один и тот же массив ArrayList, но тот же объем памяти. list = new ArrayList<int>(); собирается выделить новую память для вашего ArrayList.

Большая разница заключается в том, что ArrayLists будет динамически расширяться, поскольку вам нужно больше места. Поэтому, если вы вызываете list.clear(), у вас по-прежнему будет потенциально большой объем памяти, выделенный для ArrayList, который может не понадобиться.

Тем не менее list.clear() будет быстрее, но если вы хотите соединить макеты памяти, вы можете выделить новый ArrayList.

Ответ 8

Я бы предложил использовать list.clear() вместо выделения нового объекта. Когда вы вызываете "новое" ключевое слово, вы создаете больше места в памяти. На самом деле это не имеет большого значения. Я полагаю, что, если вы знаете, насколько велик список, может быть хорошей идеей создать новое пространство, но затем указать, насколько велик массив.

По правде говоря, это не будет иметь значения, если вы не научитесь программированию. В этом случае вам нужно учиться С++.