Why does using different ArrayList constructors cause a different growth rate of the internal array?In Java 8, why is the default capacity of ArrayList now zero?Why can't I define a static method in a Java interface?What is the ideal growth rate for a dynamically allocated array?What is the difference between google's ImmutableList and Collections.unmodifiableList ()?Returning an element from a TreeSet using binary searchCan I have someone verify my collections for the SCJP ExamHow to load file to ArrayList from src folderWhy reading byte array to an Object throws java.io.StreamCorruptedException?How Runnable is created from Java8 lambdaWhy does array[idx++]+=“a” increase idx once in Java 8 but twice in Java 9 and 10?Java - inner ArrayList loop not doing intended function

Can I travel from Germany to England alone as an unaccompanied minor?

What does BSCT stand for?

How would an order of Monks that renounce their names communicate effectively?

What are good ways to spray paint a QR code on a footpath?

Word for the ability to deliver clever replies?

Procedurally generate regions on island

Does anyone know what these symbols mean?

Can you sign using a digital signature itself?

Can 'leave' mean 'forget'?

How can a valley surrounded by mountains be fertile and rainy?

Why does a brace command group need spaces after the opening brace in POSIX Shell Grammar?

Can a Federation colony become a member world?

What game is this character in the Pixels movie from?

How can I get edges to bend to avoid crossing?

Is there a way for presidents to legally extend their terms beyond the maximum of four years?

Can someone break into a Leomund's Tiny Hut via the Ethereal Plane?

I'm reinstalling my Linux desktop, how do I keep SSH logins working?

How can I reduce the sound of rain on a range hood vent?

Acceleration in Circular motion

Spicket or spigot?

cannot execute script while its permission is 'x'

How did installing this RPM create a file?

How was film developed in the late 1920s?

What is the highest number of sneak attacks that a Pure/High Level Rogue (Level 17+) can make in one round?



Why does using different ArrayList constructors cause a different growth rate of the internal array?


In Java 8, why is the default capacity of ArrayList now zero?Why can't I define a static method in a Java interface?What is the ideal growth rate for a dynamically allocated array?What is the difference between google's ImmutableList and Collections.unmodifiableList ()?Returning an element from a TreeSet using binary searchCan I have someone verify my collections for the SCJP ExamHow to load file to ArrayList from src folderWhy reading byte array to an Object throws java.io.StreamCorruptedException?How Runnable is created from Java8 lambdaWhy does array[idx++]+=“a” increase idx once in Java 8 but twice in Java 9 and 10?Java - inner ArrayList loop not doing intended function






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








12















I seem to stumble across something interesting in ArrayList implementation that I can't wrap my head around. Here is some code that shows what I mean:



public class Sandbox 

private static final VarHandle VAR_HANDLE_ARRAY_LIST;

static
try
Lookup lookupArrayList = MethodHandles.privateLookupIn(ArrayList.class, MethodHandles.lookup());
VAR_HANDLE_ARRAY_LIST = lookupArrayList.findVarHandle(ArrayList.class, "elementData", Object[].class);
catch (Exception e)
e.printStackTrace();
throw new RuntimeException();



public static void main(String[] args)

List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");

Object[] elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(defaultConstructorList);
System.out.println(elementData.length);

List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");

elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(zeroConstructorList);
System.out.println(elementData.length);





The idea is if you create an ArrayList like this:



List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");


And look inside what the elementData (Object[] where all elements are kept) the it will report 10. Thus you add one element - you get 9 additional slots that are un-used.



If, on the other hand, you do:



List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");


you add one element, space reserved is just for that element, nothing more.



Internally this is achieved via two fields:



/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = ;

/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;



When you create an ArrayList via new ArrayList(0) - EMPTY_ELEMENTDATA will be used.



When you create an ArrayList via new Arraylist() - DEFAULTCAPACITY_EMPTY_ELEMENTDATA is used.



The intuitive part from inside me - simply screams "remove DEFAULTCAPACITY_EMPTY_ELEMENTDATA" and let all the cases be handled with EMPTY_ELEMENTDATA; of course the code comment:




We distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when first element is added




does make sense, but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested).




Even if you use List<String> zeroConstructorList = new ArrayList<>(0), and keep adding elements, eventually you will get to a point where elementData is bigger than the one requested:



 List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");
zeroConstructorList.add("two");
zeroConstructorList.add("three");
zeroConstructorList.add("four");
zeroConstructorList.add("five"); // elementData will report 6, though there are 5 elements only


But the rate at which it grows is smaller than the case of default constructor.




This reminds me about HashMap implementation, where the number of buckets is almost always more than you asked for; but there that is done because of the need for "power of two" buckets needed, not the case here though.



So the question is - can someone explain this difference to me?










share|improve this question



















  • 3





    Possible duplicate of In Java 8, why is the default capacity of ArrayList now zero?

    – Joe
    Jun 18 at 10:29






  • 3





    @Joe I have seen and read that one, but it address a different question - that explains the fact that an empty ArrayList will not have an array of size 10 anymore; the array is computed lazily - this is entirely different

    – Eugene
    Jun 18 at 10:31







  • 2





    @Eugene It's not really completely different. Notice that now we have two different strategies implemented in ArrayList where there used to be only one. To decide which strategy to use, the new constant was introduced.

    – JimmyB
    Jun 18 at 10:42











  • @JimmyB exactly the question - why are there two of them now? the idea in that Q&A is that ArrayList now, when it has no entries, will be backed up by an empty array, which can be achieved via EMPTY_ELEMENTDATA, so why keep both?

    – Eugene
    Jun 18 at 10:44






  • 1





    @Eugene I have nothing concrete to back this up, but I would imagine that it would cause hard-to-identify issues in existing code that allocated a lot of default-ctor instances, and kept adding (up to) 10 elements to them. If it grew like the new ArrayList<>(0) case, you'd end up allocating more backing arrays, and this might increase memory usage/GC usage.

    – Andy Turner
    Jun 18 at 10:50


















12















I seem to stumble across something interesting in ArrayList implementation that I can't wrap my head around. Here is some code that shows what I mean:



public class Sandbox 

private static final VarHandle VAR_HANDLE_ARRAY_LIST;

static
try
Lookup lookupArrayList = MethodHandles.privateLookupIn(ArrayList.class, MethodHandles.lookup());
VAR_HANDLE_ARRAY_LIST = lookupArrayList.findVarHandle(ArrayList.class, "elementData", Object[].class);
catch (Exception e)
e.printStackTrace();
throw new RuntimeException();



public static void main(String[] args)

List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");

Object[] elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(defaultConstructorList);
System.out.println(elementData.length);

List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");

elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(zeroConstructorList);
System.out.println(elementData.length);





The idea is if you create an ArrayList like this:



List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");


And look inside what the elementData (Object[] where all elements are kept) the it will report 10. Thus you add one element - you get 9 additional slots that are un-used.



If, on the other hand, you do:



List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");


you add one element, space reserved is just for that element, nothing more.



Internally this is achieved via two fields:



/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = ;

/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;



When you create an ArrayList via new ArrayList(0) - EMPTY_ELEMENTDATA will be used.



When you create an ArrayList via new Arraylist() - DEFAULTCAPACITY_EMPTY_ELEMENTDATA is used.



The intuitive part from inside me - simply screams "remove DEFAULTCAPACITY_EMPTY_ELEMENTDATA" and let all the cases be handled with EMPTY_ELEMENTDATA; of course the code comment:




We distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when first element is added




does make sense, but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested).




Even if you use List<String> zeroConstructorList = new ArrayList<>(0), and keep adding elements, eventually you will get to a point where elementData is bigger than the one requested:



 List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");
zeroConstructorList.add("two");
zeroConstructorList.add("three");
zeroConstructorList.add("four");
zeroConstructorList.add("five"); // elementData will report 6, though there are 5 elements only


But the rate at which it grows is smaller than the case of default constructor.




This reminds me about HashMap implementation, where the number of buckets is almost always more than you asked for; but there that is done because of the need for "power of two" buckets needed, not the case here though.



So the question is - can someone explain this difference to me?










share|improve this question



















  • 3





    Possible duplicate of In Java 8, why is the default capacity of ArrayList now zero?

    – Joe
    Jun 18 at 10:29






  • 3





    @Joe I have seen and read that one, but it address a different question - that explains the fact that an empty ArrayList will not have an array of size 10 anymore; the array is computed lazily - this is entirely different

    – Eugene
    Jun 18 at 10:31







  • 2





    @Eugene It's not really completely different. Notice that now we have two different strategies implemented in ArrayList where there used to be only one. To decide which strategy to use, the new constant was introduced.

    – JimmyB
    Jun 18 at 10:42











  • @JimmyB exactly the question - why are there two of them now? the idea in that Q&A is that ArrayList now, when it has no entries, will be backed up by an empty array, which can be achieved via EMPTY_ELEMENTDATA, so why keep both?

    – Eugene
    Jun 18 at 10:44






  • 1





    @Eugene I have nothing concrete to back this up, but I would imagine that it would cause hard-to-identify issues in existing code that allocated a lot of default-ctor instances, and kept adding (up to) 10 elements to them. If it grew like the new ArrayList<>(0) case, you'd end up allocating more backing arrays, and this might increase memory usage/GC usage.

    – Andy Turner
    Jun 18 at 10:50














12












12








12


5






I seem to stumble across something interesting in ArrayList implementation that I can't wrap my head around. Here is some code that shows what I mean:



public class Sandbox 

private static final VarHandle VAR_HANDLE_ARRAY_LIST;

static
try
Lookup lookupArrayList = MethodHandles.privateLookupIn(ArrayList.class, MethodHandles.lookup());
VAR_HANDLE_ARRAY_LIST = lookupArrayList.findVarHandle(ArrayList.class, "elementData", Object[].class);
catch (Exception e)
e.printStackTrace();
throw new RuntimeException();



public static void main(String[] args)

List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");

Object[] elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(defaultConstructorList);
System.out.println(elementData.length);

List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");

elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(zeroConstructorList);
System.out.println(elementData.length);





The idea is if you create an ArrayList like this:



List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");


And look inside what the elementData (Object[] where all elements are kept) the it will report 10. Thus you add one element - you get 9 additional slots that are un-used.



If, on the other hand, you do:



List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");


you add one element, space reserved is just for that element, nothing more.



Internally this is achieved via two fields:



/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = ;

/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;



When you create an ArrayList via new ArrayList(0) - EMPTY_ELEMENTDATA will be used.



When you create an ArrayList via new Arraylist() - DEFAULTCAPACITY_EMPTY_ELEMENTDATA is used.



The intuitive part from inside me - simply screams "remove DEFAULTCAPACITY_EMPTY_ELEMENTDATA" and let all the cases be handled with EMPTY_ELEMENTDATA; of course the code comment:




We distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when first element is added




does make sense, but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested).




Even if you use List<String> zeroConstructorList = new ArrayList<>(0), and keep adding elements, eventually you will get to a point where elementData is bigger than the one requested:



 List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");
zeroConstructorList.add("two");
zeroConstructorList.add("three");
zeroConstructorList.add("four");
zeroConstructorList.add("five"); // elementData will report 6, though there are 5 elements only


But the rate at which it grows is smaller than the case of default constructor.




This reminds me about HashMap implementation, where the number of buckets is almost always more than you asked for; but there that is done because of the need for "power of two" buckets needed, not the case here though.



So the question is - can someone explain this difference to me?










share|improve this question
















I seem to stumble across something interesting in ArrayList implementation that I can't wrap my head around. Here is some code that shows what I mean:



public class Sandbox 

private static final VarHandle VAR_HANDLE_ARRAY_LIST;

static
try
Lookup lookupArrayList = MethodHandles.privateLookupIn(ArrayList.class, MethodHandles.lookup());
VAR_HANDLE_ARRAY_LIST = lookupArrayList.findVarHandle(ArrayList.class, "elementData", Object[].class);
catch (Exception e)
e.printStackTrace();
throw new RuntimeException();



public static void main(String[] args)

List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");

Object[] elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(defaultConstructorList);
System.out.println(elementData.length);

List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");

elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(zeroConstructorList);
System.out.println(elementData.length);





The idea is if you create an ArrayList like this:



List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");


And look inside what the elementData (Object[] where all elements are kept) the it will report 10. Thus you add one element - you get 9 additional slots that are un-used.



If, on the other hand, you do:



List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");


you add one element, space reserved is just for that element, nothing more.



Internally this is achieved via two fields:



/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = ;

/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;



When you create an ArrayList via new ArrayList(0) - EMPTY_ELEMENTDATA will be used.



When you create an ArrayList via new Arraylist() - DEFAULTCAPACITY_EMPTY_ELEMENTDATA is used.



The intuitive part from inside me - simply screams "remove DEFAULTCAPACITY_EMPTY_ELEMENTDATA" and let all the cases be handled with EMPTY_ELEMENTDATA; of course the code comment:




We distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when first element is added




does make sense, but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested).




Even if you use List<String> zeroConstructorList = new ArrayList<>(0), and keep adding elements, eventually you will get to a point where elementData is bigger than the one requested:



 List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");
zeroConstructorList.add("two");
zeroConstructorList.add("three");
zeroConstructorList.add("four");
zeroConstructorList.add("five"); // elementData will report 6, though there are 5 elements only


But the rate at which it grows is smaller than the case of default constructor.




This reminds me about HashMap implementation, where the number of buckets is almost always more than you asked for; but there that is done because of the need for "power of two" buckets needed, not the case here though.



So the question is - can someone explain this difference to me?







java arraylist collections java-8 java-12






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jun 21 at 3:23









Stuart Marks

87.4k29 gold badges145 silver badges213 bronze badges




87.4k29 gold badges145 silver badges213 bronze badges










asked Jun 18 at 10:26









EugeneEugene

75.7k9 gold badges106 silver badges185 bronze badges




75.7k9 gold badges106 silver badges185 bronze badges







  • 3





    Possible duplicate of In Java 8, why is the default capacity of ArrayList now zero?

    – Joe
    Jun 18 at 10:29






  • 3





    @Joe I have seen and read that one, but it address a different question - that explains the fact that an empty ArrayList will not have an array of size 10 anymore; the array is computed lazily - this is entirely different

    – Eugene
    Jun 18 at 10:31







  • 2





    @Eugene It's not really completely different. Notice that now we have two different strategies implemented in ArrayList where there used to be only one. To decide which strategy to use, the new constant was introduced.

    – JimmyB
    Jun 18 at 10:42











  • @JimmyB exactly the question - why are there two of them now? the idea in that Q&A is that ArrayList now, when it has no entries, will be backed up by an empty array, which can be achieved via EMPTY_ELEMENTDATA, so why keep both?

    – Eugene
    Jun 18 at 10:44






  • 1





    @Eugene I have nothing concrete to back this up, but I would imagine that it would cause hard-to-identify issues in existing code that allocated a lot of default-ctor instances, and kept adding (up to) 10 elements to them. If it grew like the new ArrayList<>(0) case, you'd end up allocating more backing arrays, and this might increase memory usage/GC usage.

    – Andy Turner
    Jun 18 at 10:50













  • 3





    Possible duplicate of In Java 8, why is the default capacity of ArrayList now zero?

    – Joe
    Jun 18 at 10:29






  • 3





    @Joe I have seen and read that one, but it address a different question - that explains the fact that an empty ArrayList will not have an array of size 10 anymore; the array is computed lazily - this is entirely different

    – Eugene
    Jun 18 at 10:31







  • 2





    @Eugene It's not really completely different. Notice that now we have two different strategies implemented in ArrayList where there used to be only one. To decide which strategy to use, the new constant was introduced.

    – JimmyB
    Jun 18 at 10:42











  • @JimmyB exactly the question - why are there two of them now? the idea in that Q&A is that ArrayList now, when it has no entries, will be backed up by an empty array, which can be achieved via EMPTY_ELEMENTDATA, so why keep both?

    – Eugene
    Jun 18 at 10:44






  • 1





    @Eugene I have nothing concrete to back this up, but I would imagine that it would cause hard-to-identify issues in existing code that allocated a lot of default-ctor instances, and kept adding (up to) 10 elements to them. If it grew like the new ArrayList<>(0) case, you'd end up allocating more backing arrays, and this might increase memory usage/GC usage.

    – Andy Turner
    Jun 18 at 10:50








3




3





Possible duplicate of In Java 8, why is the default capacity of ArrayList now zero?

– Joe
Jun 18 at 10:29





Possible duplicate of In Java 8, why is the default capacity of ArrayList now zero?

– Joe
Jun 18 at 10:29




3




3





@Joe I have seen and read that one, but it address a different question - that explains the fact that an empty ArrayList will not have an array of size 10 anymore; the array is computed lazily - this is entirely different

– Eugene
Jun 18 at 10:31






@Joe I have seen and read that one, but it address a different question - that explains the fact that an empty ArrayList will not have an array of size 10 anymore; the array is computed lazily - this is entirely different

– Eugene
Jun 18 at 10:31





2




2





@Eugene It's not really completely different. Notice that now we have two different strategies implemented in ArrayList where there used to be only one. To decide which strategy to use, the new constant was introduced.

– JimmyB
Jun 18 at 10:42





@Eugene It's not really completely different. Notice that now we have two different strategies implemented in ArrayList where there used to be only one. To decide which strategy to use, the new constant was introduced.

– JimmyB
Jun 18 at 10:42













@JimmyB exactly the question - why are there two of them now? the idea in that Q&A is that ArrayList now, when it has no entries, will be backed up by an empty array, which can be achieved via EMPTY_ELEMENTDATA, so why keep both?

– Eugene
Jun 18 at 10:44





@JimmyB exactly the question - why are there two of them now? the idea in that Q&A is that ArrayList now, when it has no entries, will be backed up by an empty array, which can be achieved via EMPTY_ELEMENTDATA, so why keep both?

– Eugene
Jun 18 at 10:44




1




1





@Eugene I have nothing concrete to back this up, but I would imagine that it would cause hard-to-identify issues in existing code that allocated a lot of default-ctor instances, and kept adding (up to) 10 elements to them. If it grew like the new ArrayList<>(0) case, you'd end up allocating more backing arrays, and this might increase memory usage/GC usage.

– Andy Turner
Jun 18 at 10:50






@Eugene I have nothing concrete to back this up, but I would imagine that it would cause hard-to-identify issues in existing code that allocated a lot of default-ctor instances, and kept adding (up to) 10 elements to them. If it grew like the new ArrayList<>(0) case, you'd end up allocating more backing arrays, and this might increase memory usage/GC usage.

– Andy Turner
Jun 18 at 10:50













6 Answers
6






active

oldest

votes


















13














You get precisely what you asked for, respective what has been specified, even in older versions, where the implementation was different:



ArrayList()


Constructs an empty list with an initial capacity of ten.




ArrayList(int)


Constructs an empty list with the specified initial capacity.




So, constructing the ArrayList with the default constructor will give you an ArrayList with an initial capacity of ten, so as long as the list size is ten or smaller, no resize operation will ever be needed.



In contrast, the constructor with the int argument will precisely use the specified capacity, subject to the growing policy which is specified as




The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.




which applies even when you specify an initial capacity of zero.



Java 8 added the optimization that the creation of the ten elements array is postponed until the first element is added. This is specifically addressing the common case that ArrayList instances (created with the default capacity) stay empty for a long time or even their entire lifetime. Further, when the first actual operation is addAll, it might skip the first array resize operation. This does not affect lists with an explicit initial capacity, as those are usually chosen carefully.



As stated in this answer:




According to our performance analysis team, approximately 85% of ArrayList instances are created at default size so this optimization will be valid for an overwhelming majority of cases.




The motivation was to optimize precisely these scenarios, not to touch the specified default capacity, which was defined back when ArrayList was created. (Though JDK 1.4 is the first one specifying it explicitly)






share|improve this answer

























  • I'd consider rewording parts of the answer, since the initial capacity is in fact no longer 10 (except for an inappropriately gracious interpretation of what the "initial capacity" should mean...).

    – Marco13
    Jun 18 at 11:36






  • 6





    @Marco13 the answer uses the same wording as the specification. The initial capacity is ten; there’s just an optimization adding laziness to the first array creation. Anything else is unaffected, especially any consideration regarding whether and what to specify as alternative initial capacity when using ArrayList, does not change.

    – Holger
    Jun 18 at 11:41











  • Again, this may be considered as a nitpick about the term "initial capacity": It is, so to say, vague enough so that they could change the behavior in Java 8. But before that, "initial capacity" meant: The size of the internal array directly after construction. And this was 10. Now it is 0. Or to put it that way: If you call 10 the "initial capacity", how to you call the 0? The "pre-initial capacity"?

    – Marco13
    Jun 18 at 12:30






  • 7





    @Marco13 since that zero-sized array is not specific to the ArrayList instance, but a shared array, merely a marker that the initial size is the default one, I wouldn’t call its size “initial capacity”. They could have used null instead, but decided to use the marker array due to known interactions with the JVM’s optimizer. Besides that, I still think, that the behavior is easily understandable when describing it in terms of “initial capacity”, be it the way you expect, and then adding the fact that there is a specific optimization for a specific case, diverging from that meaning.

    – Holger
    Jun 18 at 12:43


















3














If you use the default constructor, the idea is to try to balance memory usage and reallocation. Hence a small default size (10) is used that should be fine for most applications.



If you use the constructor with an explicit size, it is assumed that you know what you're doing. If you initialize it with 0 you are essentially saying: I am pretty sure this will either stay empty or not grow beyond very few elements.



Now if you look at the implementations of ensureCapacityInternal in openjdk (link), you can see that only the first time you add an item, this difference comes into play:



private void ensureCapacityInternal(int minCapacity) 
if (elementData == EMPTY_ELEMENTDATA)
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);


ensureExplicitCapacity(minCapacity);



If the default constructor is used, the size grows to DEFAULT_CAPACITY (10). This is to prevent too many reallocations if multiple elements are added. However if you explicitly created this ArrayList with size 0, it will simply grow to size 1 on the first element you add. This is because you told it that you know what you're doing.



ensureExplicitCapacity basically just calls grow (with some range/overflow checks), so let's look at that:



private void grow(int minCapacity) 
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);



As you can see, it doesn't simply grow to a specific size, but it tries to be smart. The bigger the array is, the bigger it will grow even if minCapacity is just 1 bigger than the current capacity. The reasoning behind that is simple: The probability that a lof of items will be added is higher if the list is already big and vice versa. This is also why you see growth increments by 1 and then by 2 after the 5th element.






share|improve this answer























  • I might have to think about it a bit more, but I like your reasonings; especially the ones on the very bottom of your answer.

    – Eugene
    Jun 18 at 11:09






  • 3





    The non-linear growth is even mandatory, to provide the guaranty “that adding an element has constant amortized time cost”, as when you grow the array by one on each add, you’d end up at quadratic time costs for all added elements.

    – Holger
    Jun 18 at 11:36


















1














The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, see below.



Instead of two constants they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCapacity; but that would require additional memory per instance, which seems to be against the goal to save a few bytes of memory.



Why do we need to distinguish those two?



Looking at ensureCapacity() we see what happens with DEFAULTCAPACITY_EMPTY_ELEMENTDATA:



public void ensureCapacity(int minCapacity) 
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;

if (minCapacity > minExpand)
ensureExplicitCapacity(minCapacity);




It seems that it is done this way to be somewhat 'compatible' to the behavior of the old implementation:



If you did initialize the list with the default capacity, it will actually be initialized with an empty array now, but, as soon as the first element is inserted, it will basically revert to the same behavior as the old implementation, i.e. after the first element is added, the backing array has the DEFAULT_CAPACITY and from then on, the list behaves the same as previously.



If, on the other hand, you explicitly specifiy an inital capacity, the array does not 'jump' to DEFAULT_CAPACITY but grows relatively from your specified initial capacity.



I figure the reason for this 'optimization' may be for cases where you know you will be only storing one or two (i.e. less than DEFAULT_CAPACITY) elements in the list and you specify the initial capacity accordingly; in these cases, for example for a single-element list, you only get a single-element array, instead of a DEFAULT_CAPACITY-sized.



Don't ask me what the practical benefit is of saving nine array elements of a reference type. Might be up to about 9*64 bit = 72 bytes of RAM per list. Yeay. ;-)






share|improve this answer

























  • I appreciate your "trial" of an answer, but its only stating the same question from a different angle... and a reference is probably more like 32 bits; unless you have a pretty darn big heap.

    – Eugene
    Jun 18 at 11:02






  • 2





    I don't think it repeats the question. The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, i.e. in ensureCapacity(). Why do we need to distinguish those two? - Because we want to be compatible in one case and optimize for memory in the other case, see ensureCapacity().

    – JimmyB
    Jun 18 at 11:05











  • @Eugene Instead of two constants, they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCap; but that would require additional memory per instance, which seems to be against the goal to save memory.

    – JimmyB
    Jun 18 at 11:07












  • I guess that on 64-bit JVMs object references internally will be of the native pointer size, i.e. 64 bits. Besides, it the JVM does support more than 2GB of heap it must use pointers > 32 bits.

    – JimmyB
    Jun 18 at 11:09











  • no it doesn't. UseCompressedOops

    – Eugene
    Jun 18 at 11:10


















0














This is most likely due to the case that the two constructor have different perceived default uses.



The default (empty) constructor assumes that this will be a "typical ArrayList". Therefore, the number 10 is chosen as a sort of heuristic, aka "what the typical average number of elements inserted will be that will not take up too much space but will not grow the array needlessly too". On the other hand, the capacity constructor has the presupposition of "you know what you're doing" or "you know what you will be using the ArrayList for". Therefore, no heuristics of this type are present.






share|improve this answer






























    0















    but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested)




    Probably because most people that create lists want to store more than 1 element in it.



    You know, when you want exactly one entry, why not use Collections.singletonList() for example.



    In other words, I think the answer is pragmatism. When you use the default constructor, the typical use case would be that you are going to add maybe a handful or so of elements quickly.



    Meaning: "unknown" is interpreted as "a few", whereas "exactly 0 (or 1)" is interpreted "hmm, exactly 0 or 1".






    share|improve this answer






























      0














      The capacity with the default constructor is 10 simply because the docs say so. It would have been chosen as a sensible compromise between not using up too much memory off the bat, and not having to perform lots of array copies when adding the first few elements.



      The zero behaviour is slightly speculative, but I'm fairly confident with my reasoning here:



      It's because if you explicitly initialise an ArrayList with a size of zero, then add something to it, you're saying "I'm not expecting this list to hold much, if anything at all." It therefore makes much, much more sense to grow the backing array slowly, as though it was initialised with a value of 1, rather than treating it as if it had no initial value specified at all. So it handles the special case of growing it to just 1 element, and then carries on as normal.



      To then complete the picture, an ArrayList explicitly initialised with a size of 1 would be expected to grow much more slowly (up to the point it hits the default "10 element" size) than the default one, otherwise there'd be no reason to initialise it with a small value in the first place.






      share|improve this answer



























        Your Answer






        StackExchange.ifUsing("editor", function ()
        StackExchange.using("externalEditor", function ()
        StackExchange.using("snippets", function ()
        StackExchange.snippets.init();
        );
        );
        , "code-snippets");

        StackExchange.ready(function()
        var channelOptions =
        tags: "".split(" "),
        id: "1"
        ;
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function()
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled)
        StackExchange.using("snippets", function()
        createEditor();
        );

        else
        createEditor();

        );

        function createEditor()
        StackExchange.prepareEditor(
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader:
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        ,
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );













        draft saved

        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56647032%2fwhy-does-using-different-arraylist-constructors-cause-a-different-growth-rate-of%23new-answer', 'question_page');

        );

        Post as a guest















        Required, but never shown

























        6 Answers
        6






        active

        oldest

        votes








        6 Answers
        6






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        13














        You get precisely what you asked for, respective what has been specified, even in older versions, where the implementation was different:



        ArrayList()


        Constructs an empty list with an initial capacity of ten.




        ArrayList(int)


        Constructs an empty list with the specified initial capacity.




        So, constructing the ArrayList with the default constructor will give you an ArrayList with an initial capacity of ten, so as long as the list size is ten or smaller, no resize operation will ever be needed.



        In contrast, the constructor with the int argument will precisely use the specified capacity, subject to the growing policy which is specified as




        The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.




        which applies even when you specify an initial capacity of zero.



        Java 8 added the optimization that the creation of the ten elements array is postponed until the first element is added. This is specifically addressing the common case that ArrayList instances (created with the default capacity) stay empty for a long time or even their entire lifetime. Further, when the first actual operation is addAll, it might skip the first array resize operation. This does not affect lists with an explicit initial capacity, as those are usually chosen carefully.



        As stated in this answer:




        According to our performance analysis team, approximately 85% of ArrayList instances are created at default size so this optimization will be valid for an overwhelming majority of cases.




        The motivation was to optimize precisely these scenarios, not to touch the specified default capacity, which was defined back when ArrayList was created. (Though JDK 1.4 is the first one specifying it explicitly)






        share|improve this answer

























        • I'd consider rewording parts of the answer, since the initial capacity is in fact no longer 10 (except for an inappropriately gracious interpretation of what the "initial capacity" should mean...).

          – Marco13
          Jun 18 at 11:36






        • 6





          @Marco13 the answer uses the same wording as the specification. The initial capacity is ten; there’s just an optimization adding laziness to the first array creation. Anything else is unaffected, especially any consideration regarding whether and what to specify as alternative initial capacity when using ArrayList, does not change.

          – Holger
          Jun 18 at 11:41











        • Again, this may be considered as a nitpick about the term "initial capacity": It is, so to say, vague enough so that they could change the behavior in Java 8. But before that, "initial capacity" meant: The size of the internal array directly after construction. And this was 10. Now it is 0. Or to put it that way: If you call 10 the "initial capacity", how to you call the 0? The "pre-initial capacity"?

          – Marco13
          Jun 18 at 12:30






        • 7





          @Marco13 since that zero-sized array is not specific to the ArrayList instance, but a shared array, merely a marker that the initial size is the default one, I wouldn’t call its size “initial capacity”. They could have used null instead, but decided to use the marker array due to known interactions with the JVM’s optimizer. Besides that, I still think, that the behavior is easily understandable when describing it in terms of “initial capacity”, be it the way you expect, and then adding the fact that there is a specific optimization for a specific case, diverging from that meaning.

          – Holger
          Jun 18 at 12:43















        13














        You get precisely what you asked for, respective what has been specified, even in older versions, where the implementation was different:



        ArrayList()


        Constructs an empty list with an initial capacity of ten.




        ArrayList(int)


        Constructs an empty list with the specified initial capacity.




        So, constructing the ArrayList with the default constructor will give you an ArrayList with an initial capacity of ten, so as long as the list size is ten or smaller, no resize operation will ever be needed.



        In contrast, the constructor with the int argument will precisely use the specified capacity, subject to the growing policy which is specified as




        The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.




        which applies even when you specify an initial capacity of zero.



        Java 8 added the optimization that the creation of the ten elements array is postponed until the first element is added. This is specifically addressing the common case that ArrayList instances (created with the default capacity) stay empty for a long time or even their entire lifetime. Further, when the first actual operation is addAll, it might skip the first array resize operation. This does not affect lists with an explicit initial capacity, as those are usually chosen carefully.



        As stated in this answer:




        According to our performance analysis team, approximately 85% of ArrayList instances are created at default size so this optimization will be valid for an overwhelming majority of cases.




        The motivation was to optimize precisely these scenarios, not to touch the specified default capacity, which was defined back when ArrayList was created. (Though JDK 1.4 is the first one specifying it explicitly)






        share|improve this answer

























        • I'd consider rewording parts of the answer, since the initial capacity is in fact no longer 10 (except for an inappropriately gracious interpretation of what the "initial capacity" should mean...).

          – Marco13
          Jun 18 at 11:36






        • 6





          @Marco13 the answer uses the same wording as the specification. The initial capacity is ten; there’s just an optimization adding laziness to the first array creation. Anything else is unaffected, especially any consideration regarding whether and what to specify as alternative initial capacity when using ArrayList, does not change.

          – Holger
          Jun 18 at 11:41











        • Again, this may be considered as a nitpick about the term "initial capacity": It is, so to say, vague enough so that they could change the behavior in Java 8. But before that, "initial capacity" meant: The size of the internal array directly after construction. And this was 10. Now it is 0. Or to put it that way: If you call 10 the "initial capacity", how to you call the 0? The "pre-initial capacity"?

          – Marco13
          Jun 18 at 12:30






        • 7





          @Marco13 since that zero-sized array is not specific to the ArrayList instance, but a shared array, merely a marker that the initial size is the default one, I wouldn’t call its size “initial capacity”. They could have used null instead, but decided to use the marker array due to known interactions with the JVM’s optimizer. Besides that, I still think, that the behavior is easily understandable when describing it in terms of “initial capacity”, be it the way you expect, and then adding the fact that there is a specific optimization for a specific case, diverging from that meaning.

          – Holger
          Jun 18 at 12:43













        13












        13








        13







        You get precisely what you asked for, respective what has been specified, even in older versions, where the implementation was different:



        ArrayList()


        Constructs an empty list with an initial capacity of ten.




        ArrayList(int)


        Constructs an empty list with the specified initial capacity.




        So, constructing the ArrayList with the default constructor will give you an ArrayList with an initial capacity of ten, so as long as the list size is ten or smaller, no resize operation will ever be needed.



        In contrast, the constructor with the int argument will precisely use the specified capacity, subject to the growing policy which is specified as




        The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.




        which applies even when you specify an initial capacity of zero.



        Java 8 added the optimization that the creation of the ten elements array is postponed until the first element is added. This is specifically addressing the common case that ArrayList instances (created with the default capacity) stay empty for a long time or even their entire lifetime. Further, when the first actual operation is addAll, it might skip the first array resize operation. This does not affect lists with an explicit initial capacity, as those are usually chosen carefully.



        As stated in this answer:




        According to our performance analysis team, approximately 85% of ArrayList instances are created at default size so this optimization will be valid for an overwhelming majority of cases.




        The motivation was to optimize precisely these scenarios, not to touch the specified default capacity, which was defined back when ArrayList was created. (Though JDK 1.4 is the first one specifying it explicitly)






        share|improve this answer















        You get precisely what you asked for, respective what has been specified, even in older versions, where the implementation was different:



        ArrayList()


        Constructs an empty list with an initial capacity of ten.




        ArrayList(int)


        Constructs an empty list with the specified initial capacity.




        So, constructing the ArrayList with the default constructor will give you an ArrayList with an initial capacity of ten, so as long as the list size is ten or smaller, no resize operation will ever be needed.



        In contrast, the constructor with the int argument will precisely use the specified capacity, subject to the growing policy which is specified as




        The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.




        which applies even when you specify an initial capacity of zero.



        Java 8 added the optimization that the creation of the ten elements array is postponed until the first element is added. This is specifically addressing the common case that ArrayList instances (created with the default capacity) stay empty for a long time or even their entire lifetime. Further, when the first actual operation is addAll, it might skip the first array resize operation. This does not affect lists with an explicit initial capacity, as those are usually chosen carefully.



        As stated in this answer:




        According to our performance analysis team, approximately 85% of ArrayList instances are created at default size so this optimization will be valid for an overwhelming majority of cases.




        The motivation was to optimize precisely these scenarios, not to touch the specified default capacity, which was defined back when ArrayList was created. (Though JDK 1.4 is the first one specifying it explicitly)







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jun 18 at 11:30

























        answered Jun 18 at 11:22









        HolgerHolger

        178k24 gold badges260 silver badges486 bronze badges




        178k24 gold badges260 silver badges486 bronze badges












        • I'd consider rewording parts of the answer, since the initial capacity is in fact no longer 10 (except for an inappropriately gracious interpretation of what the "initial capacity" should mean...).

          – Marco13
          Jun 18 at 11:36






        • 6





          @Marco13 the answer uses the same wording as the specification. The initial capacity is ten; there’s just an optimization adding laziness to the first array creation. Anything else is unaffected, especially any consideration regarding whether and what to specify as alternative initial capacity when using ArrayList, does not change.

          – Holger
          Jun 18 at 11:41











        • Again, this may be considered as a nitpick about the term "initial capacity": It is, so to say, vague enough so that they could change the behavior in Java 8. But before that, "initial capacity" meant: The size of the internal array directly after construction. And this was 10. Now it is 0. Or to put it that way: If you call 10 the "initial capacity", how to you call the 0? The "pre-initial capacity"?

          – Marco13
          Jun 18 at 12:30






        • 7





          @Marco13 since that zero-sized array is not specific to the ArrayList instance, but a shared array, merely a marker that the initial size is the default one, I wouldn’t call its size “initial capacity”. They could have used null instead, but decided to use the marker array due to known interactions with the JVM’s optimizer. Besides that, I still think, that the behavior is easily understandable when describing it in terms of “initial capacity”, be it the way you expect, and then adding the fact that there is a specific optimization for a specific case, diverging from that meaning.

          – Holger
          Jun 18 at 12:43

















        • I'd consider rewording parts of the answer, since the initial capacity is in fact no longer 10 (except for an inappropriately gracious interpretation of what the "initial capacity" should mean...).

          – Marco13
          Jun 18 at 11:36






        • 6





          @Marco13 the answer uses the same wording as the specification. The initial capacity is ten; there’s just an optimization adding laziness to the first array creation. Anything else is unaffected, especially any consideration regarding whether and what to specify as alternative initial capacity when using ArrayList, does not change.

          – Holger
          Jun 18 at 11:41











        • Again, this may be considered as a nitpick about the term "initial capacity": It is, so to say, vague enough so that they could change the behavior in Java 8. But before that, "initial capacity" meant: The size of the internal array directly after construction. And this was 10. Now it is 0. Or to put it that way: If you call 10 the "initial capacity", how to you call the 0? The "pre-initial capacity"?

          – Marco13
          Jun 18 at 12:30






        • 7





          @Marco13 since that zero-sized array is not specific to the ArrayList instance, but a shared array, merely a marker that the initial size is the default one, I wouldn’t call its size “initial capacity”. They could have used null instead, but decided to use the marker array due to known interactions with the JVM’s optimizer. Besides that, I still think, that the behavior is easily understandable when describing it in terms of “initial capacity”, be it the way you expect, and then adding the fact that there is a specific optimization for a specific case, diverging from that meaning.

          – Holger
          Jun 18 at 12:43
















        I'd consider rewording parts of the answer, since the initial capacity is in fact no longer 10 (except for an inappropriately gracious interpretation of what the "initial capacity" should mean...).

        – Marco13
        Jun 18 at 11:36





        I'd consider rewording parts of the answer, since the initial capacity is in fact no longer 10 (except for an inappropriately gracious interpretation of what the "initial capacity" should mean...).

        – Marco13
        Jun 18 at 11:36




        6




        6





        @Marco13 the answer uses the same wording as the specification. The initial capacity is ten; there’s just an optimization adding laziness to the first array creation. Anything else is unaffected, especially any consideration regarding whether and what to specify as alternative initial capacity when using ArrayList, does not change.

        – Holger
        Jun 18 at 11:41





        @Marco13 the answer uses the same wording as the specification. The initial capacity is ten; there’s just an optimization adding laziness to the first array creation. Anything else is unaffected, especially any consideration regarding whether and what to specify as alternative initial capacity when using ArrayList, does not change.

        – Holger
        Jun 18 at 11:41













        Again, this may be considered as a nitpick about the term "initial capacity": It is, so to say, vague enough so that they could change the behavior in Java 8. But before that, "initial capacity" meant: The size of the internal array directly after construction. And this was 10. Now it is 0. Or to put it that way: If you call 10 the "initial capacity", how to you call the 0? The "pre-initial capacity"?

        – Marco13
        Jun 18 at 12:30





        Again, this may be considered as a nitpick about the term "initial capacity": It is, so to say, vague enough so that they could change the behavior in Java 8. But before that, "initial capacity" meant: The size of the internal array directly after construction. And this was 10. Now it is 0. Or to put it that way: If you call 10 the "initial capacity", how to you call the 0? The "pre-initial capacity"?

        – Marco13
        Jun 18 at 12:30




        7




        7





        @Marco13 since that zero-sized array is not specific to the ArrayList instance, but a shared array, merely a marker that the initial size is the default one, I wouldn’t call its size “initial capacity”. They could have used null instead, but decided to use the marker array due to known interactions with the JVM’s optimizer. Besides that, I still think, that the behavior is easily understandable when describing it in terms of “initial capacity”, be it the way you expect, and then adding the fact that there is a specific optimization for a specific case, diverging from that meaning.

        – Holger
        Jun 18 at 12:43





        @Marco13 since that zero-sized array is not specific to the ArrayList instance, but a shared array, merely a marker that the initial size is the default one, I wouldn’t call its size “initial capacity”. They could have used null instead, but decided to use the marker array due to known interactions with the JVM’s optimizer. Besides that, I still think, that the behavior is easily understandable when describing it in terms of “initial capacity”, be it the way you expect, and then adding the fact that there is a specific optimization for a specific case, diverging from that meaning.

        – Holger
        Jun 18 at 12:43













        3














        If you use the default constructor, the idea is to try to balance memory usage and reallocation. Hence a small default size (10) is used that should be fine for most applications.



        If you use the constructor with an explicit size, it is assumed that you know what you're doing. If you initialize it with 0 you are essentially saying: I am pretty sure this will either stay empty or not grow beyond very few elements.



        Now if you look at the implementations of ensureCapacityInternal in openjdk (link), you can see that only the first time you add an item, this difference comes into play:



        private void ensureCapacityInternal(int minCapacity) 
        if (elementData == EMPTY_ELEMENTDATA)
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);


        ensureExplicitCapacity(minCapacity);



        If the default constructor is used, the size grows to DEFAULT_CAPACITY (10). This is to prevent too many reallocations if multiple elements are added. However if you explicitly created this ArrayList with size 0, it will simply grow to size 1 on the first element you add. This is because you told it that you know what you're doing.



        ensureExplicitCapacity basically just calls grow (with some range/overflow checks), so let's look at that:



        private void grow(int minCapacity) 
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);



        As you can see, it doesn't simply grow to a specific size, but it tries to be smart. The bigger the array is, the bigger it will grow even if minCapacity is just 1 bigger than the current capacity. The reasoning behind that is simple: The probability that a lof of items will be added is higher if the list is already big and vice versa. This is also why you see growth increments by 1 and then by 2 after the 5th element.






        share|improve this answer























        • I might have to think about it a bit more, but I like your reasonings; especially the ones on the very bottom of your answer.

          – Eugene
          Jun 18 at 11:09






        • 3





          The non-linear growth is even mandatory, to provide the guaranty “that adding an element has constant amortized time cost”, as when you grow the array by one on each add, you’d end up at quadratic time costs for all added elements.

          – Holger
          Jun 18 at 11:36















        3














        If you use the default constructor, the idea is to try to balance memory usage and reallocation. Hence a small default size (10) is used that should be fine for most applications.



        If you use the constructor with an explicit size, it is assumed that you know what you're doing. If you initialize it with 0 you are essentially saying: I am pretty sure this will either stay empty or not grow beyond very few elements.



        Now if you look at the implementations of ensureCapacityInternal in openjdk (link), you can see that only the first time you add an item, this difference comes into play:



        private void ensureCapacityInternal(int minCapacity) 
        if (elementData == EMPTY_ELEMENTDATA)
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);


        ensureExplicitCapacity(minCapacity);



        If the default constructor is used, the size grows to DEFAULT_CAPACITY (10). This is to prevent too many reallocations if multiple elements are added. However if you explicitly created this ArrayList with size 0, it will simply grow to size 1 on the first element you add. This is because you told it that you know what you're doing.



        ensureExplicitCapacity basically just calls grow (with some range/overflow checks), so let's look at that:



        private void grow(int minCapacity) 
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);



        As you can see, it doesn't simply grow to a specific size, but it tries to be smart. The bigger the array is, the bigger it will grow even if minCapacity is just 1 bigger than the current capacity. The reasoning behind that is simple: The probability that a lof of items will be added is higher if the list is already big and vice versa. This is also why you see growth increments by 1 and then by 2 after the 5th element.






        share|improve this answer























        • I might have to think about it a bit more, but I like your reasonings; especially the ones on the very bottom of your answer.

          – Eugene
          Jun 18 at 11:09






        • 3





          The non-linear growth is even mandatory, to provide the guaranty “that adding an element has constant amortized time cost”, as when you grow the array by one on each add, you’d end up at quadratic time costs for all added elements.

          – Holger
          Jun 18 at 11:36













        3












        3








        3







        If you use the default constructor, the idea is to try to balance memory usage and reallocation. Hence a small default size (10) is used that should be fine for most applications.



        If you use the constructor with an explicit size, it is assumed that you know what you're doing. If you initialize it with 0 you are essentially saying: I am pretty sure this will either stay empty or not grow beyond very few elements.



        Now if you look at the implementations of ensureCapacityInternal in openjdk (link), you can see that only the first time you add an item, this difference comes into play:



        private void ensureCapacityInternal(int minCapacity) 
        if (elementData == EMPTY_ELEMENTDATA)
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);


        ensureExplicitCapacity(minCapacity);



        If the default constructor is used, the size grows to DEFAULT_CAPACITY (10). This is to prevent too many reallocations if multiple elements are added. However if you explicitly created this ArrayList with size 0, it will simply grow to size 1 on the first element you add. This is because you told it that you know what you're doing.



        ensureExplicitCapacity basically just calls grow (with some range/overflow checks), so let's look at that:



        private void grow(int minCapacity) 
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);



        As you can see, it doesn't simply grow to a specific size, but it tries to be smart. The bigger the array is, the bigger it will grow even if minCapacity is just 1 bigger than the current capacity. The reasoning behind that is simple: The probability that a lof of items will be added is higher if the list is already big and vice versa. This is also why you see growth increments by 1 and then by 2 after the 5th element.






        share|improve this answer













        If you use the default constructor, the idea is to try to balance memory usage and reallocation. Hence a small default size (10) is used that should be fine for most applications.



        If you use the constructor with an explicit size, it is assumed that you know what you're doing. If you initialize it with 0 you are essentially saying: I am pretty sure this will either stay empty or not grow beyond very few elements.



        Now if you look at the implementations of ensureCapacityInternal in openjdk (link), you can see that only the first time you add an item, this difference comes into play:



        private void ensureCapacityInternal(int minCapacity) 
        if (elementData == EMPTY_ELEMENTDATA)
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);


        ensureExplicitCapacity(minCapacity);



        If the default constructor is used, the size grows to DEFAULT_CAPACITY (10). This is to prevent too many reallocations if multiple elements are added. However if you explicitly created this ArrayList with size 0, it will simply grow to size 1 on the first element you add. This is because you told it that you know what you're doing.



        ensureExplicitCapacity basically just calls grow (with some range/overflow checks), so let's look at that:



        private void grow(int minCapacity) 
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);



        As you can see, it doesn't simply grow to a specific size, but it tries to be smart. The bigger the array is, the bigger it will grow even if minCapacity is just 1 bigger than the current capacity. The reasoning behind that is simple: The probability that a lof of items will be added is higher if the list is already big and vice versa. This is also why you see growth increments by 1 and then by 2 after the 5th element.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jun 18 at 11:05









        Max VollmerMax Vollmer

        6,2825 gold badges21 silver badges38 bronze badges




        6,2825 gold badges21 silver badges38 bronze badges












        • I might have to think about it a bit more, but I like your reasonings; especially the ones on the very bottom of your answer.

          – Eugene
          Jun 18 at 11:09






        • 3





          The non-linear growth is even mandatory, to provide the guaranty “that adding an element has constant amortized time cost”, as when you grow the array by one on each add, you’d end up at quadratic time costs for all added elements.

          – Holger
          Jun 18 at 11:36

















        • I might have to think about it a bit more, but I like your reasonings; especially the ones on the very bottom of your answer.

          – Eugene
          Jun 18 at 11:09






        • 3





          The non-linear growth is even mandatory, to provide the guaranty “that adding an element has constant amortized time cost”, as when you grow the array by one on each add, you’d end up at quadratic time costs for all added elements.

          – Holger
          Jun 18 at 11:36
















        I might have to think about it a bit more, but I like your reasonings; especially the ones on the very bottom of your answer.

        – Eugene
        Jun 18 at 11:09





        I might have to think about it a bit more, but I like your reasonings; especially the ones on the very bottom of your answer.

        – Eugene
        Jun 18 at 11:09




        3




        3





        The non-linear growth is even mandatory, to provide the guaranty “that adding an element has constant amortized time cost”, as when you grow the array by one on each add, you’d end up at quadratic time costs for all added elements.

        – Holger
        Jun 18 at 11:36





        The non-linear growth is even mandatory, to provide the guaranty “that adding an element has constant amortized time cost”, as when you grow the array by one on each add, you’d end up at quadratic time costs for all added elements.

        – Holger
        Jun 18 at 11:36











        1














        The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, see below.



        Instead of two constants they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCapacity; but that would require additional memory per instance, which seems to be against the goal to save a few bytes of memory.



        Why do we need to distinguish those two?



        Looking at ensureCapacity() we see what happens with DEFAULTCAPACITY_EMPTY_ELEMENTDATA:



        public void ensureCapacity(int minCapacity) 
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

        if (minCapacity > minExpand)
        ensureExplicitCapacity(minCapacity);




        It seems that it is done this way to be somewhat 'compatible' to the behavior of the old implementation:



        If you did initialize the list with the default capacity, it will actually be initialized with an empty array now, but, as soon as the first element is inserted, it will basically revert to the same behavior as the old implementation, i.e. after the first element is added, the backing array has the DEFAULT_CAPACITY and from then on, the list behaves the same as previously.



        If, on the other hand, you explicitly specifiy an inital capacity, the array does not 'jump' to DEFAULT_CAPACITY but grows relatively from your specified initial capacity.



        I figure the reason for this 'optimization' may be for cases where you know you will be only storing one or two (i.e. less than DEFAULT_CAPACITY) elements in the list and you specify the initial capacity accordingly; in these cases, for example for a single-element list, you only get a single-element array, instead of a DEFAULT_CAPACITY-sized.



        Don't ask me what the practical benefit is of saving nine array elements of a reference type. Might be up to about 9*64 bit = 72 bytes of RAM per list. Yeay. ;-)






        share|improve this answer

























        • I appreciate your "trial" of an answer, but its only stating the same question from a different angle... and a reference is probably more like 32 bits; unless you have a pretty darn big heap.

          – Eugene
          Jun 18 at 11:02






        • 2





          I don't think it repeats the question. The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, i.e. in ensureCapacity(). Why do we need to distinguish those two? - Because we want to be compatible in one case and optimize for memory in the other case, see ensureCapacity().

          – JimmyB
          Jun 18 at 11:05











        • @Eugene Instead of two constants, they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCap; but that would require additional memory per instance, which seems to be against the goal to save memory.

          – JimmyB
          Jun 18 at 11:07












        • I guess that on 64-bit JVMs object references internally will be of the native pointer size, i.e. 64 bits. Besides, it the JVM does support more than 2GB of heap it must use pointers > 32 bits.

          – JimmyB
          Jun 18 at 11:09











        • no it doesn't. UseCompressedOops

          – Eugene
          Jun 18 at 11:10















        1














        The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, see below.



        Instead of two constants they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCapacity; but that would require additional memory per instance, which seems to be against the goal to save a few bytes of memory.



        Why do we need to distinguish those two?



        Looking at ensureCapacity() we see what happens with DEFAULTCAPACITY_EMPTY_ELEMENTDATA:



        public void ensureCapacity(int minCapacity) 
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

        if (minCapacity > minExpand)
        ensureExplicitCapacity(minCapacity);




        It seems that it is done this way to be somewhat 'compatible' to the behavior of the old implementation:



        If you did initialize the list with the default capacity, it will actually be initialized with an empty array now, but, as soon as the first element is inserted, it will basically revert to the same behavior as the old implementation, i.e. after the first element is added, the backing array has the DEFAULT_CAPACITY and from then on, the list behaves the same as previously.



        If, on the other hand, you explicitly specifiy an inital capacity, the array does not 'jump' to DEFAULT_CAPACITY but grows relatively from your specified initial capacity.



        I figure the reason for this 'optimization' may be for cases where you know you will be only storing one or two (i.e. less than DEFAULT_CAPACITY) elements in the list and you specify the initial capacity accordingly; in these cases, for example for a single-element list, you only get a single-element array, instead of a DEFAULT_CAPACITY-sized.



        Don't ask me what the practical benefit is of saving nine array elements of a reference type. Might be up to about 9*64 bit = 72 bytes of RAM per list. Yeay. ;-)






        share|improve this answer

























        • I appreciate your "trial" of an answer, but its only stating the same question from a different angle... and a reference is probably more like 32 bits; unless you have a pretty darn big heap.

          – Eugene
          Jun 18 at 11:02






        • 2





          I don't think it repeats the question. The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, i.e. in ensureCapacity(). Why do we need to distinguish those two? - Because we want to be compatible in one case and optimize for memory in the other case, see ensureCapacity().

          – JimmyB
          Jun 18 at 11:05











        • @Eugene Instead of two constants, they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCap; but that would require additional memory per instance, which seems to be against the goal to save memory.

          – JimmyB
          Jun 18 at 11:07












        • I guess that on 64-bit JVMs object references internally will be of the native pointer size, i.e. 64 bits. Besides, it the JVM does support more than 2GB of heap it must use pointers > 32 bits.

          – JimmyB
          Jun 18 at 11:09











        • no it doesn't. UseCompressedOops

          – Eugene
          Jun 18 at 11:10













        1












        1








        1







        The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, see below.



        Instead of two constants they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCapacity; but that would require additional memory per instance, which seems to be against the goal to save a few bytes of memory.



        Why do we need to distinguish those two?



        Looking at ensureCapacity() we see what happens with DEFAULTCAPACITY_EMPTY_ELEMENTDATA:



        public void ensureCapacity(int minCapacity) 
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

        if (minCapacity > minExpand)
        ensureExplicitCapacity(minCapacity);




        It seems that it is done this way to be somewhat 'compatible' to the behavior of the old implementation:



        If you did initialize the list with the default capacity, it will actually be initialized with an empty array now, but, as soon as the first element is inserted, it will basically revert to the same behavior as the old implementation, i.e. after the first element is added, the backing array has the DEFAULT_CAPACITY and from then on, the list behaves the same as previously.



        If, on the other hand, you explicitly specifiy an inital capacity, the array does not 'jump' to DEFAULT_CAPACITY but grows relatively from your specified initial capacity.



        I figure the reason for this 'optimization' may be for cases where you know you will be only storing one or two (i.e. less than DEFAULT_CAPACITY) elements in the list and you specify the initial capacity accordingly; in these cases, for example for a single-element list, you only get a single-element array, instead of a DEFAULT_CAPACITY-sized.



        Don't ask me what the practical benefit is of saving nine array elements of a reference type. Might be up to about 9*64 bit = 72 bytes of RAM per list. Yeay. ;-)






        share|improve this answer















        The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, see below.



        Instead of two constants they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCapacity; but that would require additional memory per instance, which seems to be against the goal to save a few bytes of memory.



        Why do we need to distinguish those two?



        Looking at ensureCapacity() we see what happens with DEFAULTCAPACITY_EMPTY_ELEMENTDATA:



        public void ensureCapacity(int minCapacity) 
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

        if (minCapacity > minExpand)
        ensureExplicitCapacity(minCapacity);




        It seems that it is done this way to be somewhat 'compatible' to the behavior of the old implementation:



        If you did initialize the list with the default capacity, it will actually be initialized with an empty array now, but, as soon as the first element is inserted, it will basically revert to the same behavior as the old implementation, i.e. after the first element is added, the backing array has the DEFAULT_CAPACITY and from then on, the list behaves the same as previously.



        If, on the other hand, you explicitly specifiy an inital capacity, the array does not 'jump' to DEFAULT_CAPACITY but grows relatively from your specified initial capacity.



        I figure the reason for this 'optimization' may be for cases where you know you will be only storing one or two (i.e. less than DEFAULT_CAPACITY) elements in the list and you specify the initial capacity accordingly; in these cases, for example for a single-element list, you only get a single-element array, instead of a DEFAULT_CAPACITY-sized.



        Don't ask me what the practical benefit is of saving nine array elements of a reference type. Might be up to about 9*64 bit = 72 bytes of RAM per list. Yeay. ;-)







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jun 18 at 11:19

























        answered Jun 18 at 10:59









        JimmyBJimmyB

        9,8891 gold badge18 silver badges38 bronze badges




        9,8891 gold badge18 silver badges38 bronze badges












        • I appreciate your "trial" of an answer, but its only stating the same question from a different angle... and a reference is probably more like 32 bits; unless you have a pretty darn big heap.

          – Eugene
          Jun 18 at 11:02






        • 2





          I don't think it repeats the question. The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, i.e. in ensureCapacity(). Why do we need to distinguish those two? - Because we want to be compatible in one case and optimize for memory in the other case, see ensureCapacity().

          – JimmyB
          Jun 18 at 11:05











        • @Eugene Instead of two constants, they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCap; but that would require additional memory per instance, which seems to be against the goal to save memory.

          – JimmyB
          Jun 18 at 11:07












        • I guess that on 64-bit JVMs object references internally will be of the native pointer size, i.e. 64 bits. Besides, it the JVM does support more than 2GB of heap it must use pointers > 32 bits.

          – JimmyB
          Jun 18 at 11:09











        • no it doesn't. UseCompressedOops

          – Eugene
          Jun 18 at 11:10

















        • I appreciate your "trial" of an answer, but its only stating the same question from a different angle... and a reference is probably more like 32 bits; unless you have a pretty darn big heap.

          – Eugene
          Jun 18 at 11:02






        • 2





          I don't think it repeats the question. The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, i.e. in ensureCapacity(). Why do we need to distinguish those two? - Because we want to be compatible in one case and optimize for memory in the other case, see ensureCapacity().

          – JimmyB
          Jun 18 at 11:05











        • @Eugene Instead of two constants, they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCap; but that would require additional memory per instance, which seems to be against the goal to save memory.

          – JimmyB
          Jun 18 at 11:07












        • I guess that on 64-bit JVMs object references internally will be of the native pointer size, i.e. 64 bits. Besides, it the JVM does support more than 2GB of heap it must use pointers > 32 bits.

          – JimmyB
          Jun 18 at 11:09











        • no it doesn't. UseCompressedOops

          – Eugene
          Jun 18 at 11:10
















        I appreciate your "trial" of an answer, but its only stating the same question from a different angle... and a reference is probably more like 32 bits; unless you have a pretty darn big heap.

        – Eugene
        Jun 18 at 11:02





        I appreciate your "trial" of an answer, but its only stating the same question from a different angle... and a reference is probably more like 32 bits; unless you have a pretty darn big heap.

        – Eugene
        Jun 18 at 11:02




        2




        2





        I don't think it repeats the question. The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, i.e. in ensureCapacity(). Why do we need to distinguish those two? - Because we want to be compatible in one case and optimize for memory in the other case, see ensureCapacity().

        – JimmyB
        Jun 18 at 11:05





        I don't think it repeats the question. The short answer to your question is what is in the Java doc: We have two constants because we now need to be able to distinguish the two different initializations later, i.e. in ensureCapacity(). Why do we need to distinguish those two? - Because we want to be compatible in one case and optimize for memory in the other case, see ensureCapacity().

        – JimmyB
        Jun 18 at 11:05













        @Eugene Instead of two constants, they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCap; but that would require additional memory per instance, which seems to be against the goal to save memory.

        – JimmyB
        Jun 18 at 11:07






        @Eugene Instead of two constants, they could of course have introduced e.g. a boolean field in ArrayList, private boolean initializedWithDefaultCap; but that would require additional memory per instance, which seems to be against the goal to save memory.

        – JimmyB
        Jun 18 at 11:07














        I guess that on 64-bit JVMs object references internally will be of the native pointer size, i.e. 64 bits. Besides, it the JVM does support more than 2GB of heap it must use pointers > 32 bits.

        – JimmyB
        Jun 18 at 11:09





        I guess that on 64-bit JVMs object references internally will be of the native pointer size, i.e. 64 bits. Besides, it the JVM does support more than 2GB of heap it must use pointers > 32 bits.

        – JimmyB
        Jun 18 at 11:09













        no it doesn't. UseCompressedOops

        – Eugene
        Jun 18 at 11:10





        no it doesn't. UseCompressedOops

        – Eugene
        Jun 18 at 11:10











        0














        This is most likely due to the case that the two constructor have different perceived default uses.



        The default (empty) constructor assumes that this will be a "typical ArrayList". Therefore, the number 10 is chosen as a sort of heuristic, aka "what the typical average number of elements inserted will be that will not take up too much space but will not grow the array needlessly too". On the other hand, the capacity constructor has the presupposition of "you know what you're doing" or "you know what you will be using the ArrayList for". Therefore, no heuristics of this type are present.






        share|improve this answer



























          0














          This is most likely due to the case that the two constructor have different perceived default uses.



          The default (empty) constructor assumes that this will be a "typical ArrayList". Therefore, the number 10 is chosen as a sort of heuristic, aka "what the typical average number of elements inserted will be that will not take up too much space but will not grow the array needlessly too". On the other hand, the capacity constructor has the presupposition of "you know what you're doing" or "you know what you will be using the ArrayList for". Therefore, no heuristics of this type are present.






          share|improve this answer

























            0












            0








            0







            This is most likely due to the case that the two constructor have different perceived default uses.



            The default (empty) constructor assumes that this will be a "typical ArrayList". Therefore, the number 10 is chosen as a sort of heuristic, aka "what the typical average number of elements inserted will be that will not take up too much space but will not grow the array needlessly too". On the other hand, the capacity constructor has the presupposition of "you know what you're doing" or "you know what you will be using the ArrayList for". Therefore, no heuristics of this type are present.






            share|improve this answer













            This is most likely due to the case that the two constructor have different perceived default uses.



            The default (empty) constructor assumes that this will be a "typical ArrayList". Therefore, the number 10 is chosen as a sort of heuristic, aka "what the typical average number of elements inserted will be that will not take up too much space but will not grow the array needlessly too". On the other hand, the capacity constructor has the presupposition of "you know what you're doing" or "you know what you will be using the ArrayList for". Therefore, no heuristics of this type are present.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Jun 18 at 11:02









            Piotr WilkinPiotr Wilkin

            2,6663 silver badges15 bronze badges




            2,6663 silver badges15 bronze badges





















                0















                but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested)




                Probably because most people that create lists want to store more than 1 element in it.



                You know, when you want exactly one entry, why not use Collections.singletonList() for example.



                In other words, I think the answer is pragmatism. When you use the default constructor, the typical use case would be that you are going to add maybe a handful or so of elements quickly.



                Meaning: "unknown" is interpreted as "a few", whereas "exactly 0 (or 1)" is interpreted "hmm, exactly 0 or 1".






                share|improve this answer



























                  0















                  but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested)




                  Probably because most people that create lists want to store more than 1 element in it.



                  You know, when you want exactly one entry, why not use Collections.singletonList() for example.



                  In other words, I think the answer is pragmatism. When you use the default constructor, the typical use case would be that you are going to add maybe a handful or so of elements quickly.



                  Meaning: "unknown" is interpreted as "a few", whereas "exactly 0 (or 1)" is interpreted "hmm, exactly 0 or 1".






                  share|improve this answer

























                    0












                    0








                    0








                    but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested)




                    Probably because most people that create lists want to store more than 1 element in it.



                    You know, when you want exactly one entry, why not use Collections.singletonList() for example.



                    In other words, I think the answer is pragmatism. When you use the default constructor, the typical use case would be that you are going to add maybe a handful or so of elements quickly.



                    Meaning: "unknown" is interpreted as "a few", whereas "exactly 0 (or 1)" is interpreted "hmm, exactly 0 or 1".






                    share|improve this answer














                    but why would one inflate to 10 (a lot more than I asked for) and the other one to 1 (exactly as much as I requested)




                    Probably because most people that create lists want to store more than 1 element in it.



                    You know, when you want exactly one entry, why not use Collections.singletonList() for example.



                    In other words, I think the answer is pragmatism. When you use the default constructor, the typical use case would be that you are going to add maybe a handful or so of elements quickly.



                    Meaning: "unknown" is interpreted as "a few", whereas "exactly 0 (or 1)" is interpreted "hmm, exactly 0 or 1".







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jun 18 at 11:15









                    GhostCatGhostCat

                    104k17 gold badges100 silver badges177 bronze badges




                    104k17 gold badges100 silver badges177 bronze badges





















                        0














                        The capacity with the default constructor is 10 simply because the docs say so. It would have been chosen as a sensible compromise between not using up too much memory off the bat, and not having to perform lots of array copies when adding the first few elements.



                        The zero behaviour is slightly speculative, but I'm fairly confident with my reasoning here:



                        It's because if you explicitly initialise an ArrayList with a size of zero, then add something to it, you're saying "I'm not expecting this list to hold much, if anything at all." It therefore makes much, much more sense to grow the backing array slowly, as though it was initialised with a value of 1, rather than treating it as if it had no initial value specified at all. So it handles the special case of growing it to just 1 element, and then carries on as normal.



                        To then complete the picture, an ArrayList explicitly initialised with a size of 1 would be expected to grow much more slowly (up to the point it hits the default "10 element" size) than the default one, otherwise there'd be no reason to initialise it with a small value in the first place.






                        share|improve this answer





























                          0














                          The capacity with the default constructor is 10 simply because the docs say so. It would have been chosen as a sensible compromise between not using up too much memory off the bat, and not having to perform lots of array copies when adding the first few elements.



                          The zero behaviour is slightly speculative, but I'm fairly confident with my reasoning here:



                          It's because if you explicitly initialise an ArrayList with a size of zero, then add something to it, you're saying "I'm not expecting this list to hold much, if anything at all." It therefore makes much, much more sense to grow the backing array slowly, as though it was initialised with a value of 1, rather than treating it as if it had no initial value specified at all. So it handles the special case of growing it to just 1 element, and then carries on as normal.



                          To then complete the picture, an ArrayList explicitly initialised with a size of 1 would be expected to grow much more slowly (up to the point it hits the default "10 element" size) than the default one, otherwise there'd be no reason to initialise it with a small value in the first place.






                          share|improve this answer



























                            0












                            0








                            0







                            The capacity with the default constructor is 10 simply because the docs say so. It would have been chosen as a sensible compromise between not using up too much memory off the bat, and not having to perform lots of array copies when adding the first few elements.



                            The zero behaviour is slightly speculative, but I'm fairly confident with my reasoning here:



                            It's because if you explicitly initialise an ArrayList with a size of zero, then add something to it, you're saying "I'm not expecting this list to hold much, if anything at all." It therefore makes much, much more sense to grow the backing array slowly, as though it was initialised with a value of 1, rather than treating it as if it had no initial value specified at all. So it handles the special case of growing it to just 1 element, and then carries on as normal.



                            To then complete the picture, an ArrayList explicitly initialised with a size of 1 would be expected to grow much more slowly (up to the point it hits the default "10 element" size) than the default one, otherwise there'd be no reason to initialise it with a small value in the first place.






                            share|improve this answer















                            The capacity with the default constructor is 10 simply because the docs say so. It would have been chosen as a sensible compromise between not using up too much memory off the bat, and not having to perform lots of array copies when adding the first few elements.



                            The zero behaviour is slightly speculative, but I'm fairly confident with my reasoning here:



                            It's because if you explicitly initialise an ArrayList with a size of zero, then add something to it, you're saying "I'm not expecting this list to hold much, if anything at all." It therefore makes much, much more sense to grow the backing array slowly, as though it was initialised with a value of 1, rather than treating it as if it had no initial value specified at all. So it handles the special case of growing it to just 1 element, and then carries on as normal.



                            To then complete the picture, an ArrayList explicitly initialised with a size of 1 would be expected to grow much more slowly (up to the point it hits the default "10 element" size) than the default one, otherwise there'd be no reason to initialise it with a small value in the first place.







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Jun 18 at 13:21

























                            answered Jun 18 at 11:11









                            Michael BerryMichael Berry

                            45.1k16 gold badges115 silver badges170 bronze badges




                            45.1k16 gold badges115 silver badges170 bronze badges



























                                draft saved

                                draft discarded
















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid


                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.

                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56647032%2fwhy-does-using-different-arraylist-constructors-cause-a-different-growth-rate-of%23new-answer', 'question_page');

                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Get product attribute by attribute group code in magento 2get product attribute by product attribute group in magento 2Magento 2 Log Bundle Product Data in List Page?How to get all product attribute of a attribute group of Default attribute set?Magento 2.1 Create a filter in the product grid by new attributeMagento 2 : Get Product Attribute values By GroupMagento 2 How to get all existing values for one attributeMagento 2 get custom attribute of a single product inside a pluginMagento 2.3 How to get all the Multi Source Inventory (MSI) locations collection in custom module?Magento2: how to develop rest API to get new productsGet product attribute by attribute group code ( [attribute_group_code] ) in magento 2

                                Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

                                Magento 2.3: How do i solve this, Not registered handle, on custom form?How can i rewrite TierPrice Block in Magento2magento 2 captcha not rendering if I override layout xmlmain.CRITICAL: Plugin class doesn't existMagento 2 : Problem while adding custom button order view page?Magento 2.2.5: Overriding Admin Controller sales/orderMagento 2.2.5: Add, Update and Delete existing products Custom OptionsMagento 2.3 : File Upload issue in UI Component FormMagento2 Not registered handleHow to configured Form Builder Js in my custom magento 2.3.0 module?Magento 2.3. How to create image upload field in an admin form