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

283

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

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

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

ateiob
источник
Возможное следствие этого вопроса: когда один может быть использован вместо другого?
Кори Огберн
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намного быстрее.

Geoff
источник
15

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

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

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

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

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

Йоахим Зауэр
источник
7

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

lucapette
источник
Можете
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, прежде чем удалять его.

CDelaney
источник
-8

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

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

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