ArrayList.ensureCapacity should expand the default capacity empty array
Martin Buchholz
martinrb at google.com
Tue Jul 10 00:34:44 UTC 2018
Thanks Alex,
I filed
https://bugs.openjdk.java.net/browse/JDK-8206945
I've had similar thoughts for years, but none have ended up in the actual
code.
I haven't seem the approach you used in your reallocate.
On Thu, Jul 5, 2018 at 10:04 AM, Alex Foster <alexfoster at hotmail.ca> wrote:
> Hi,
>
>
> I think that ensureCapacity should actually ensure the capacity by
> expanding the default capacity empty array, otherwise you could end up with
> a situation like this:
>
> List<ArrayList<Object>> ls = getLists();// Large list of ArrayLists
> ls.forEach(l -> l.ensureCapacity(10));
> //later...
> ArrayList<Object> a = ls.get(0);
> if(a.size() < 10) a.add(null); // throws OutOfMemoryError when
> array is allocated
>
> I think it's still OK to not allocate the array directly in the no-arg
> constructor because if users actually care about the capacity they can call
> the constructor with an initialCapacity argument or ensureCapacity, but
> maybe a note should be added that it can be allocated lazily?
>
> Also it's debatable if ensureCapacity should call grow or just resize the
> array to exactly the minCapacity argument, which might save space if the
> exact size needed is known, or maybe to max(minCapacity, DEFAULT_CAPACITY)
> if elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA which would use more
> space but otherwise ensureCapacity could cause you to end up with lower
> than default capacity (which might be wanted).
>
> diff --git a/src/java.base/share/classes/java/util/ArrayList.java
> b/src/java.base/share/classes/java/util/ArrayList.java
> --- a/src/java.base/share/classes/java/util/ArrayList.java
> +++ b/src/java.base/share/classes/java/util/ArrayList.java
> @@ -210,11 +210,9 @@
> * @param minCapacity the desired minimum capacity
> */
> public void ensureCapacity(int minCapacity) {
> - if (minCapacity > elementData.length
> - && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
> - && minCapacity <= DEFAULT_CAPACITY)) {
> + if (minCapacity > elementData.length) {
> modCount++;
> - grow(minCapacity);
> + elementData = Arrays.copyOf(elementData, minCapacity);
> }
> }
>
> I noticed this while writing a similar method for ArrayDeque which could
> also be added to ArrayList:
>
> /**
> * Attempts to reallocate the backing array so that is has space for
> as close as
> * possible to, but not less than, minSize elements unless it already
> has space
> * for between minSize and maxSize elements. If the size() of this
> ArrayDeque is
> * greater than minSize then size() will be treated as minSize.
> *
> * <p>This method can be used to achieve the same result as {@link
> ArrayList#trimToSize}
> * by calling {@code reallocate(0, 0)} or {@link
> ArrayList#ensureCapacity(n)} by calling
> * {@code reallocate(n, Integer.MAX_VALUE)}.
> *
> * @param minSize the requested minimum capacity
> * @param maxSize the requested maximum capacity
> * @return the new (or unchanged) capacity
> * @throws IllegalArgumentException if minSize > maxSize (size() may
> be greater than maxSize
> * without throwing an exception)
> * @throws OutOfMemoryError if there is not enough memory available to
> allocate
> * the array or the array would be larger than an implementation
> defined limit
> */
> public int reallocate(int minSize, int maxSize){
> if(minSize > maxSize) throw new IllegalArgumentException(minSize
> + " > " + maxSize);
> int c = elements.length - 1, s = size();
> if(c < minSize){
> if(minSize + 1 < 0) throw new OutOfMemoryError();
> } else {
> if(c <= maxSize) return c;
> if(s > minSize){
> if(c == (minSize = s)) return c;
> }
> }
> elements = minSize == 0 ? EMPTY : copyElements(new Object[minSize
> + 1], head, tail);
> head = 0;
> tail = s;
> return minSize;
> }
>
>
More information about the core-libs-dev
mailing list