Чим відрізняється ArrayList.clear () від ArrayList.removeAll ()?


283

Якщо припустити, що arraylistвизначено як ArrayList<String> arraylist, arraylist.removeAll(arraylist)еквівалентно arraylist.clear()?

Якщо так, чи можна вважати, що clear()метод є більш ефективним для випорожнення списку масивів?

Чи є якісь застереження у використанні arraylist.removeAll(arraylist)замість arraylist.clear()?


Можливий наслідок цього питання: Коли можна використовувати один замість іншого?
Corey Ogburn

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 ) на відміну від clear'O (n).


29
Зауважте, що c.contains(...)квадрати часової складності операції зробили б цю відповідь повною.
Atreys

8
Джерело сильне в цьому. (На всі інші відповіді: Використовуйте джерело, Лука.) Зауважте, наскільки чіткий () може бути реалізований як лише один рядок, розмір = 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
@Farid Вибачте, моя англійська мова тут занадто неформальна. Я дійсно мав на увазі, що він встановлює нуль всі елементи. Я це виправлю!
Ернест Фрідман-Хілл

7

Якщо не буде специфічної оптимізації, яка перевіряє, чи переданий аргумент removeAll()є самою колекцією (і я дуже сумніваюся, що така оптимізація існує), вона буде значно повільнішою, ніж проста .clear().

Крім того (і, принаймні, не менш важливо): arraylist.removeAll(arraylist)це просто тупий, заплутаний код. Це дуже зворотний спосіб сказати "очистити цю колекцію". Яку перевагу вона мала б над дуже зрозумілою arraylist.clear() ?


7

Вони служать різним цілям. clear()очищає екземпляр класу, removeAll()видаляє всі задані об'єкти і повертає стан операції.


Ви можете, будь ласка, надати ресурс для читання вищезазначених питань для подальшої довідки
Касун Сіямбалапітія

1
@KasunSiyambalapitiya Як щодо прийнятої відповіді , яка містить вихідний код для двох?
Абдул

5

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

removeAll(collection)пройде перевірку ArrayList на колекцію, і remove(Object)якщо вона існує.

Я б міг уявити, що clear()це спосіб швидше, ніж RemoveAll, тому що він не порівнює і т.д.


2

Очищення швидше, оскільки воно не перетинає елементи для видалення. Цей метод може припускати, що ВСІ елементи можна видалити.

Remove allне обов'язково означає видалення всіх елементів зі списку, слід видалити лише ті, що надані як параметри. Отже, потрібно докласти більше зусиль, щоб зберегти ті, які не слід видаляти.

КЛАФІКАЦІЯ

Під "циклом" я маю на увазі, що він не повинен перевіряти, чи слід зберігати елемент чи ні. Він може встановити посилання nullбез пошуку через надані списки елементів для видалення.

ClearЄ швидше, ніж deleteall.


1
Я майже впевнений, що ArrayList.clear()і в цьому циклі.
Йоахім Зауер

@JVerstry Ви маєте на увазі, що clear () не видаляє елементи, які він видаляє з ArrayList?
ateiob

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

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

2
-3 трохи суворо. Якщо JVerstry захотів, він міг написати власну реалізацію Java з нуля, що не циклічно. clear () може бути реалізовано в O (1), без циклу, тоді як RemoveAll () ОБОВ'ЯЗКОВО має бути якийсь алгоритм O (n), немає можливості виконати контракт APIAAAAAAAAAAAAAAAAAAAAAAAAAAA не перевіряючи всі елементи.
Джуліус Мюсо

1

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


-8

Array => щойно проміжок виділяється для змінної масиву Array під час виконання, виділений простір неможливо розширити чи видалити.

ArrayList => У arraylist це не так. ArrayList може рости і скорочуватися під час виконання. Виділений простір можна мінімізувати або збільшити на час виконання.


Це не відповідає на питання, яка різниця між ArrayList.clear () та ArrayList.removeAll (), а не різниця між ArrayList і ArrayList.
П’єр

Ця відповідь зайва. Про це не йдеться.
Серафім Коста
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.