Qual è la differenza tra ArrayList.clear () e ArrayList.removeAll ()?


283

Supponendo che arraylistsia definito come ArrayList<String> arraylist, è arraylist.removeAll(arraylist)equivalente a arraylist.clear()?

In tal caso, posso supporre che il clear()metodo sia più efficiente per svuotare l'elenco di array?

Ci sono avvertenze nell'uso arraylist.removeAll(arraylist)invece di arraylist.clear()?


Un possibile corollario di questa domanda: quando si potrebbe usare uno anziché l'altro?
Corey Ogburn,

3
@Corey: quando uno potrebbe voler usare tutti arraylist.removeAll(arraylist)? Non vedo assolutamente alcun motivo per farlo.
Joachim Sauer,

@Joachim Sauer Questo è esattamente ciò che volevo verificare. Grazie +2. Ma la differenza tra elementData[i] = nulle è e.remove()significativa?
ateiob,

Non c'è motivo ragionevole di fare arrList.removeAll(arrList)invece di arrList.clear(). arrList1.removeAll(arrList2)è una questione diversa.
Vlad

3
Se solo l'implementazione di removeAll () fosse iniziata con questa linea, allora l'intera discussione avrebbe potuto essere molto più divertente !!! if (c == this && !isEmpty()) { clear(); return true; }. Dovrò inviarlo a OpenJDK come patch! ;-)
Julius Musseau l'

Risposte:


396

Il codice sorgente per clear():

public void clear() {
    modCount++;

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

    size = 0;
}

Il codice sorgente per removeAll()(come definito in 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() è molto più veloce poiché non ha a che fare con tutte quelle chiamate di metodo extra.

E come sottolinea Atrey, c.contains(..)aumenta la complessità temporale di removeAlla O (n 2 ) rispetto a clearO (n).


29
Una nota che c.contains(...)quadra la complessità temporale dell'operazione renderebbe completa questa risposta.
Atreys,

8
La fonte è forte in questo. (A tutte le altre risposte: usa la fonte, Luke.) Nota come clear () potrebbe essere implementato come una sola riga, size = 0; ma la garbage-collection non saprebbe raccogliere gli elementi nelle porzioni irraggiungibili dell'array.
Julius Musseau,

2
e.remove () è molto più complesso! e.remove () anche quadrare la complessità, proprio come c.contains (...). Su un ArrayList, e.remove () chiama ArrayList.remove (int index), che deve spostare il resto dell'array di uno.
Julius Musseau,

1
@ateiob e.remove () sono due chiamate di metodo extra, un controllo di intervallo e anche un ritorno di oggetto (interno a AbstractList.Itr.remove()e ArrayList.remove(int))
Atreys

2
@julius Se lo facesse: size = 0; elementData = new Object[10];tutto il resto verrebbe raccolto, dato che l'array di supporto non ha riferimenti esterni.
corsiKa

51

La complessità temporale di ArrayList.clear()is O(n)e of removeAllis O(n^2).

Quindi sì, ArrayList.clearè molto più veloce.


15

Il clear()metodo rimuove tutti gli elementi di un singolo ArrayList. È un'operazione veloce, in quanto imposta semplicemente gli elementi dell'array su null.

Il removeAll(Collection)metodo, da cui è ereditato AbstractCollection, rimuove tutti gli elementi presenti nella raccolta argomenti dalla raccolta su cui si chiama il metodo. È un'operazione relativamente lenta, poiché deve cercare in una delle raccolte coinvolte.


Ho pensato che imposta tutto, non alcuni elementi su null. In caso contrario, come ha deciso quali elementi devono essere impostati su null?
Farid,

2
@Farid mi dispiace, il mio inglese è fin troppo informale qui. Intendevo davvero dire che imposta tutti gli elementi su null. Lo aggiusterò!
Ernest Friedman-Hill,

7

A meno che non ci sia un'ottimizzazione specifica che controlla se l'argomento passato removeAll()è la raccolta stessa (e dubito fortemente che tale ottimizzazione sia presente) sarà significativamente più lenta di una semplice .clear().

A parte questo (e almeno altrettanto importante): arraylist.removeAll(arraylist)è solo un codice ottuso e confuso. È un modo molto arretrato di dire "cancella questa raccolta". Quale vantaggio avrebbe rispetto al molto comprensibile arraylist.clear() ?


7

Servono a scopi diversi. clear()cancella un'istanza della classe, removeAll()rimuove tutti gli oggetti dati e restituisce lo stato dell'operazione.


puoi per favore fornire una risorsa da leggere sull'argomento di cui sopra per ulteriori riferimenti
Kasun Siyambalapitiya,

1
@KasunSiyambalapitiya Che ne dici della risposta accettata , che contiene il codice sorgente per i due?
Abdul,

5

clear() passerà attraverso l'array sottostante e imposterà ogni voce su null;

removeAll(collection)passerà attraverso ArrayList controllando la raccolta e remove(Object)se esiste.

Immagino che clear()sia molto più veloce quindi rimuovi Tutto perché non sta confrontando, ecc.


2

La cancellazione è più veloce perché non passa sopra gli elementi da eliminare. Questo metodo può presumere che TUTTI gli elementi possano essere eliminati.

Remove allnon significa necessariamente eliminare tutti gli elementi nell'elenco, solo quelli forniti come parametri DOVREBBERO essere eliminati. Pertanto, è necessario uno sforzo maggiore per mantenere quelli che non devono essere eliminati.

UNA PRECISAZIONE

Con "loop", intendo che non è necessario verificare se l'elemento deve essere mantenuto o meno. Può impostare il riferimento su nullsenza cercare negli elenchi di elementi forniti da eliminare.

ClearÈ più veloce di deleteall.


1
Sono abbastanza sicuro che anche questo ArrayList.clear()debba essere ripetuto.
Joachim Sauer,

@JVerstry Vuoi dire che clear () non elimina gli elementi che rimuove dalla ArrayList?
ateiob,

1
Wrong, clear esegue un ciclo sull'array interno e imposta tutti i riferimenti su null per consentire al garbage collector di svolgere il proprio lavoro.
Devconsole,

1
@Joachim, @devconsole: penso che intendesse dire che non dovrà scorrere / iterare l'elenco indicato come parametro. target.removeAll(param)ripeterà parame poi chiamerà su target.contains(...)cui ripeterà target.
Vlad

2
-3 è un po 'duro. Se JVerstry lo avesse voluto, avrebbe potuto scrivere da zero la propria implementazione Java che non funzionava. clear () può essere implementato in O (1), senza un ciclo, mentre removeAll () DEVE avere un qualche tipo di algoritmo O (n), non c'è modo di soddisfare il contratto dell'API removeAll () senza esaminare tutti gli elementi.
Julius Musseau,

1

clear () sarà molto più efficiente. Rimuoverà semplicemente ogni singolo elemento. L'uso di removeAll (arraylist) richiederà molto più lavoro perché controllerà ogni elemento dell'arraylist per vedere se esiste nell'arraylist prima di rimuoverlo.


-8

Array => una volta assegnato lo spazio per una variabile Array in fase di esecuzione, lo spazio allocato non può essere esteso o rimosso.

ArrayList => Questo non è il caso dell'arraylist. ArrayList può crescere e ridursi in fase di esecuzione. Lo spazio allocato può essere ridotto a icona o ingrandito in fase di esecuzione.


Questo non risponde alla domanda che è la differenza tra ArrayList.clear () e ArrayList.removeAll (), non la differenza tra un array e un array.
Pierre,

Questa risposta non è necessaria. Non è di questo che si tratta.
Serafim Costa,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.