139

Which one of the 2 options is better and faster to clear an ArrayList, and why?

list.clear() 

or

list = new ArrayList<Integer>();

It happens that I have to, at random times, clear all entries from my ArrayList and I have no way to know how many new entries there will be in the future, there might be 0 or a 1000. Which method is faster and better, and why?

madth3
  • 7,275
  • 12
  • 50
  • 74
Greg
  • 2,039
  • 3
  • 19
  • 26
  • 1
    They are different. Use the suitable one for the task. Since I like to minimize side-effects, I *often* choose the latter. Worrying about "performance" here is ... likely silly. –  Aug 05 '11 at 19:05
  • 1
    How are you using primitive types in generics? You must use wrapper classes. – Ryan Amos Aug 05 '11 at 19:06
  • 1
    have you performed any benchmarking tests? that would be the best way to find out. – Matt K Aug 05 '11 at 19:07
  • 3
    Answer may also depend on whether you share your list. If it's a shared list, then others using it might be surprised that it is empty after you call clear. But if you allocate a new list, it doesn't get rid of the references (if the first list was shared) – Atreys Aug 05 '11 at 19:16

8 Answers8

79

It's hard to know without a benchmark, but if you have lots of items in your ArrayList and the average size is lower, it might be faster to make a new 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;
}
Bono
  • 4,757
  • 6
  • 48
  • 77
dfb
  • 13,133
  • 2
  • 31
  • 52
  • 39
    +1 For showing the source. It's interesting to note that `clear` *does not* resize the backing array. –  Aug 05 '11 at 19:07
  • 9
    @pst: This is an interesting point-- if the ArrayList is going to be cleared and refilled with hundreds of items repeatedly, it might be faster to use `.clear()` and thus prevent the array copy that occurs when size exceeds capacity on an `.add(Object)` call. – Platinum Azure Aug 05 '11 at 19:12
  • 13
    Note, a new ArrayList will also take O(n) time - new Object[n] requires nulling every slots. – irreputable Aug 05 '11 at 19:40
  • 4
    @PlatinumAzure: That's not really an advantage for clear, because you can set the initial capacity of an ArrayList? – Buttons840 Sep 19 '11 at 22:27
  • 4
    @irreputable - However, one difference is that clear() does the operation with an explicit loop (in Java), but for `new Object[n]` the nulling is done by the GC using a bulk memory zeroing mechanism that one would expect to be faster; e.g. hand optimized C++ or ASM, or even clever virtual memory tricks. – Stephen C Jun 10 '13 at 23:16
  • @user166390 you can use 'trimToSize()', to update the size of the current list to the real array size (no the old array size) – Genaut Jun 11 '17 at 20:50
  • Hello @StephenC, I would like to confirm if you are suggesting that for an existing array list with large number of inputs, `arrLst = new ArrayList<>(arrLst.size());` might be better than `arrLst.clear();` or `arrLst = new ArrayList<>();`? – experiment unit 1998X Feb 10 '23 at 02:48
  • 1
    Yes. That is confirmed. – Stephen C Feb 10 '23 at 03:10
29

List.clear would remove the elements without reducing the capacity of the list.

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

Here mylist got cleared, the references to the elements held by it got nulled out, but it keeps the same backing array. Then mylist was reinitialized and got a new backing array, the old one got GCed. So one way holds onto memory, the other one throws out its memory and gets reallocated from scratch (with the default capacity). Which is better depends on whether you want to reduce garbage-collection churn or minimize the current amount of unused memory. Whether the list sticks around long enough to be moved out of Eden might be a factor in deciding which is faster (because that might make garbage-collecting it more expensive).

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
21

I think that the answer is that it depends on a whole range of factors such as:

  • whether the list size can be predicted beforehand (i.e. can you set the capacity accurately),
  • whether the list size is variable (i.e. each time it is filled),
  • how long the lifetime of the list will be in both versions, and
  • your heap / GC parameters and CPU.

These make it hard to predict which will be better. But my intuition is that the difference will not be that great.

Two bits of advice on optimization:

  • Don't waste time trying to optimize this ... unless the application is objectively too slow AND measurement using a profiler tells you that this is a performance hotspot. (The chances are that one of those preconditions won't be true.)

  • If you do decide to optimize this, do it scientifically. Try both (all) of the alternatives and decide which is best by measuring the performance in your actual application on a realistic problem / workload / input set. (An artificial benchmark is liable to give you answers that do not predict real-world behavior, because of factors like those I listed previously.)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
17

The first one .clear(); will keep the same list just clear the list.

The second one new ArrayList<Integer>(); creates a new ArrayList in memory.

Suggestion: First one because that's what is is designed to do.

madth3
  • 7,275
  • 12
  • 50
  • 74
RMT
  • 7,040
  • 4
  • 25
  • 37
  • 8
    Sure, `clear` is designed to clear the list -- but how is that fundamentally better than using a *new* empty list? –  Aug 05 '11 at 19:07
  • 1
    Actually, it will not create a new ArrayList in memory, instead it will replace the old list. It will not use more memory. The old list will be dumped. – Ricardo Fiorani Mar 31 '15 at 23:20
  • @RicardoFiorani The answer doesn't say it will use more. It will indeed create a new ArrayList in memory, the old memory won't be re-used until the old ArrayList is garbage-collected. – Matthew Read Apr 11 '15 at 17:52
  • 1
    @RMT : Answer sounds unarguable. – theapache64 May 20 '16 at 10:32
  • Sure, if the list is big or not, a clear help to java know that can use the gc (wihout guaranties), creating a new list maybe can be more fast than loop a big for, but you are keeping in memory a lot of objects (big list) maybe a lot of time. Anyway, use clear with "trimtoSize()" method to update the size property with the real value (not old value size) – Genaut Jun 11 '17 at 20:54
  • Sure, obviously `clear()` to clear the list, but there is a large gap in your logic between "a way" and "the best way". And as a counter argument, I would say that `clear()` could have been implemented as the best way to deal with cases where you *cannot* create a new list. For example, because the list reference has been published to other parts of your application, and it is impractical to find and update all of the variables where the reference may be held. – Stephen C Apr 09 '19 at 23:41
6

Tried the below program , With both the approach. 1. With clearing the arraylist obj in for loop 2. creating new New Arraylist in for loop.

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();

        }

and to my surprise. the memory allocation didnt change much.

With New Arraylist approach.

Before loop total free memory: 64,909 ::

After loop total free memory: 64,775 ::

with Clear approach,

Before loop total free memory: 64,909 :: After loop total free memory: 64,765 ::

So this says there is not much difference in using arraylist.clear from memory utilization perspective.

vishal
  • 69
  • 1
  • 1
  • 14
    IMHO 10 and 100 are way too small number to test this. – Helin Wang Apr 28 '14 at 14:37
  • 1
    There shouldn't be any difference in memory usage since you end up without only the outer ArrayList not garbage-collected. This doesn't address the performance concerns in the question at all, it's not an answer. – Matthew Read Apr 11 '15 at 17:43
4

If there is a good chance that the list will contain as much elements as it contains when clearing it, and if you're not in need for free memory, clearing the list is a better option. But my guess is that it probably doesn't matter. Don't try to optimize until you have detected a performance problem, and identified where it comes from.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
2

list.clear() is going to keep the same ArrayList but the same memory allocation. list = new ArrayList<int>(); is going to allocate new memory for your ArrayList.

The big difference is that ArrayLists will expand dynamically as you need more space. Therefore, if you call list.clear() you will still, potentially, have a large amount of memory allocated for an ArrayList that might not be needed.

That said list.clear() will be faster but if memory maters you might want to allocate a new ArrayList.

J Lundberg
  • 2,313
  • 2
  • 20
  • 23
1

I would suggest using list.clear() rather than allocating a new object. When you call the "new" keyword, you are creating more space in memory. In reality, it doesn't matter much. I suppose that if you know how large the list will be, it might be a good idea to create a new space but then specify how large the array will be.

The truth is, it's not going to matter unless you're doing scientific programming. In that case, you need to go learn C++.

Ryan Amos
  • 5,422
  • 4
  • 36
  • 56