8

Be aware, it is not a duplicate of Why start an ArrayList with an initial capacity?

Looking into the source code of the java.util.ArrayList class, starting from at least java 1.8 I see the following code:

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

Where

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

Though the javadoc officially states:

Constructs an empty list with an initial capacity of ten.

I outline: ...an initial capacity of ten. Where is this ten?

Am I completely mad and missing something, or there is simply a javadoc bug here?

UPD: How it looked like prior java 1.8:

public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = new Object[initialCapacity];
}

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this(10);
}
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
Andremoniy
  • 34,031
  • 20
  • 135
  • 241

2 Answers2

8

This is an optimization. The developers decided to initialize the ArrayList with an empty backing array, and lazily create a non-empty backing array only when you start adding elements to the List.

When you add the first element (by calling add), it calls

ensureCapacityInternal(size + 1);

which checks if elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA, and if so, sets the capacity to

minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

DEFAULT_CAPACITY is 10.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • But I still don't get, it is explicitly said: *an initial capacity of ten*. Where is this *ten*? :p – Andremoniy Dec 13 '18 at 13:51
  • @Andremoniy see edit – Eran Dec 13 '18 at 13:52
  • I see. It's a good catch. No doubts. HOWEVER. There is a big difference for those who only reads the javadoc: before java 1.8 it would make sense to create ```ArrayList(0)``` to make it a slightly more efficient, isn't it? So I would insist that this is a kind of bug in javadoc... – Andremoniy Dec 13 '18 at 13:54
  • 1
    @Andremoniy I'm not sure it's a bug in javadoc. I'd call it an implementation detail. – Eran Dec 13 '18 at 13:56
  • Could you check please, where this `ensureCapacityInternal` is called? It seems to me that by calling just ```ArrayList::add``` it won't be enlarged to `10` elements... – Andremoniy Dec 13 '18 at 13:57
  • 1
    @Andremoniy `add` calls `ensureCapacityInternal(1)` (when the list is empty), which calls `ensureExplicitCapacity(10)`, which calls `grow(10)`, which calls `elementData = Arrays.copyOf(elementData, newCapacity);` – Eran Dec 13 '18 at 14:00
  • That's true, I've also checked. Thanks. – Andremoniy Dec 13 '18 at 14:02
  • @Andremoniy I think this is not a documentation error because another implementation (based on OpenJDK) may decide to revert to the Java 7 way of initializing the capacity to 10, and still be compliant with the official documentation. (Correct me if I'm wrong, but I think Oracle's Java API documentation does not just document the Oracle implementation, but all conforming JDKs). – DodgyCodeException Dec 13 '18 at 14:05
  • It almost certainly is a "bug" in the JavaDocs. The JavaDocs are describing the situation before Java 8, and simply have not been updated. (One could certainly argue about the meaning of "initial capacity", but even if it means "initial capacity *after the first element was added*", it would still be confusing) – Marco13 Dec 13 '18 at 21:35
3

The capacity will be set as 10 when you add element to the list first time.

See this:

/**
 * Default initial capacity.
 */
private static final int DEFAULT_CAPACITY = 10;

Complete procedure

Step 1:

public boolean add(E e) {
    modCount++;
    add(e, elementData, size);
    return true;
}

Step 2:

private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)
        elementData = grow();
    elementData[s] = e;
    size = s + 1;
}

Step 3, the list grows:

private Object[] grow() {
    return grow(size + 1); // size is 0 here
}

private Object[] grow(int minCapacity) {
    return elementData = Arrays.copyOf(elementData,
                                       newCapacity(minCapacity));  // newCapacity(1) will return 10, see step 4, the elementData will have capacity 10.
}

Step 4, call newCapacity(1):

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity <= 0) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            return Math.max(DEFAULT_CAPACITY, minCapacity);   // will  return 10 here !!!!
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return minCapacity;
    }
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        : hugeCapacity(minCapacity);
}
xingbin
  • 27,410
  • 9
  • 53
  • 103