В чем разница между ArrayList.clear () и ArrayList.removeAll ()?


283

Предполагая, что arraylistопределяется как ArrayList<String> arraylist, arraylist.removeAll(arraylist)эквивалентно arraylist.clear()?

Если да, могу ли я предположить, что clear()метод более эффективен для очистки списка массивов?

Есть ли какие-то предостережения в использовании arraylist.removeAll(arraylist)вместо arraylist.clear()?


Возможное следствие этого вопроса: когда один может быть использован вместо другого?
Кори Огберн

3
@Corey: когда каждый может захотеть использовать arraylist.removeAll(arraylist)? Я не вижу абсолютно никаких причин для этого.
Иоахим Зауэр

@Joachim Sauer Это именно то, что я хотел проверить. Спасибо +2. Но разница между elementData[i] = nullи e.remove()значительным?
ateiob

Там нет разумной причины, чтобы сделать arrList.removeAll(arrList)вместо arrList.clear(). arrList1.removeAll(arrList2)это другое дело.
Влад

3
Если бы только реализация removeAll () началась с этой строки, тогда вся эта дискуссия могла бы быть намного более интересной !!! if (c == this && !isEmpty()) { clear(); return true; }, Я должен представить это OpenJDK как патч! ;-)
Джулиус Муссо

Ответы:


396

Исходный код для clear():

public void clear() {
    modCount++;

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

    size = 0;
}

Исходный код removeAll()(как определено в AbstractCollection):

public boolean removeAll(Collection<?> c) {
    boolean modified = false;
    Iterator<?> e = iterator();
    while (e.hasNext()) {
        if (c.contains(e.next())) {
            e.remove();
            modified = true;
        }
    }
    return modified;
}

clear() намного быстрее, так как он не должен иметь дело со всеми этими дополнительными вызовами методов.

И, как указывает Атри, c.contains(..)увеличивает временную сложность removeAllдо O (n 2 ), а не clearO (n).


29
Примечание, которое c.contains(...)возводит в квадрат временную сложность операции, сделает этот ответ завершенным.
Atreys

8
Источник сильный в этом. (Для всех остальных ответов: используйте источник, Люк.) Обратите внимание, как clear () может быть реализована как одна строка, size = 0; но сборщик мусора не будет знать, как собирать элементы в недоступных частях массива.
Юлий Муссо

2
e.remove () намного сложнее! e.remove () также возводит в квадрат сложность, как c.contains (...). В ArrayList e.remove () вызывает ArrayList.remove (int index), который должен сдвинуть остаток массива на единицу.
Юлий Муссо

1
@ateiob e.remove () - это два дополнительных вызова метода, проверка диапазона и возврат объекта (внутри AbstractList.Itr.remove()и ArrayList.remove(int))
Atreys

2
@julius Если бы он сделал это: size = 0; elementData = new Object[10];все остальное было бы собрано мусором, поскольку резервный массив не имеет внешних ссылок.
CorsiKa

51

Сложность времени ArrayList.clear()есть O(n)и removeAllесть O(n^2).

Так что да, ArrayList.clearнамного быстрее.


15

clear()Метод удаляет все элементы одного ArrayList. Это быстрая операция, так как она просто устанавливает элементы массива в null.

removeAll(Collection)Метод, который наследуется от AbstractCollectionудаляет все элементы , которые находятся в коллекции аргументов из коллекции вы вызовите метод. Это относительно медленная операция, поскольку она должна искать в одной из участвующих коллекций.


Я думал, что это просто устанавливает все, а не некоторые элементы в ноль. Если это не так, как он решил, какие элементы должны быть установлены в нуль?
Фарид

2
@ Прошу прощения, мой английский здесь слишком неформальный. Я действительно имел в виду, что он устанавливает все элементы в нуль. Я исправлю это!
Эрнест Фридман-Хилл

7

Если нет специальной оптимизации, которая проверяет, является ли передаваемый аргумент removeAll()самой коллекцией (и я очень сомневаюсь, что такая оптимизация есть), она будет значительно медленнее, чем простая .clear().

Помимо этого (и, по крайней мере, не менее важно): arraylist.removeAll(arraylist)просто тупой, запутанный код. Это очень обратный способ сказать «очистить эту коллекцию». Какое преимущество это будет иметь над очень понятным arraylist.clear() ?


7

Они служат разным целям. clear()очищает экземпляр класса, removeAll()удаляет все заданные объекты и возвращает состояние операции.



1
@KasunSiyambalapitiya Как насчет принятого ответа , который содержит исходный код для двух?
Абдул

5

clear() будет проходить через основной массив и устанавливать каждую запись на ноль;

removeAll(collection)будет проходить проверку ArrayList для сбора и remove(Object)его, если он существует.

Я полагаю, что clear()это намного быстрее, чем удалить все, потому что это не сравнение и т. Д.


2

Очистить быстрее, потому что он не зацикливает элементы для удаления. Этот метод может предполагать, что ВСЕ элементы могут быть удалены.

Remove allне обязательно означает удаление всех элементов в списке, ДОЛЖНЫ быть удалены только те, которые указаны в качестве параметров. Следовательно, требуется больше усилий, чтобы сохранить те, которые не следует удалять.

ПОЯСНЕНИЯ

Под «циклом» я подразумеваю, что он не должен проверять, должен ли элемент сохраняться или нет. Он может установить ссылку nullбез поиска в предоставленных списках элементов для удаления.

ClearБыстрее чем deleteall.


1
Я уверен, что это ArrayList.clear()тоже должно пройти.
Иоахим Зауэр

@JVerstry Вы имеете в виду, что clear () не удаляет элементы, которые он удаляет из ArrayList?
ateiob

1
Неправильно, clear делает цикл по внутреннему массиву и устанавливает все ссылки на null, чтобы позволить сборщику мусора выполнять свою работу.
devconsole

1
@Joachim, @devconsole: Я думаю, он имел в виду, что не нужно будет циклически повторять список, указанный в качестве параметра. target.removeAll(param)будет перебирать, paramа затем вызывать, target.contains(...)который перебирает target.
Влад

2
-3 немного грубовато. Если бы JVerstry хотел, он мог бы написать свою собственную реализацию Java с нуля, которая не была зациклена. clear () может быть реально реализована в O (1) без цикла, тогда как removeAll () ДОЛЖЕН иметь некоторый алгоритм O (n), нет способа удовлетворить контракт API removeAll () без проверки всех элементов.
Юлий Муссо

1

clear () будет намного эффективнее. Это просто удалит каждый элемент. Использование removeAll (arraylist) потребует намного больше работы, потому что он проверит каждый элемент в arraylist, чтобы увидеть, существует ли он в arraylist, прежде чем удалять его.


-8

Array => как только пространство выделено для переменной Array во время выполнения, выделенное пространство не может быть расширено или удалено.

ArrayList => Это не так в arraylist. ArrayList может расти и уменьшаться во время выполнения. Выделенное пространство может быть минимизировано или максимизировано во время выполнения.


Это не отвечает на вопрос, в чем заключается различие между ArrayList.clear () и ArrayList.removeAll (), а не в разнице между Array и ArrayList.
Пьер

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