Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass zero-sized array, save allocation?

In this code sample from page 114 of The Well-Grounded Java Developer, the last line:

Update[] updates = lu.toArray(new Update[0]);

contains the note: Pass zero-sized array, save allocation

List<Update> lu = new ArrayList<Update>();
String text = "";
final Update.Builder ub = new Update.Builder();
final Author a = new Author("Tallulah");

for (int i=0; i<256; i++) {
  text = text + "X";
  long now = System.currentTimeMillis();
  lu.add(ub.author(a).updateText(text).createTime(now).build());
  try {
    Thread.sleep(1);
  } catch (InterruptedException e) {
  }
}

Collections.shuffle(lu);
Update[] updates = lu.toArray(new Update[0]);

What allocation is this saving, exactly?

The javadoc for List#toArray(T[] a) mentions:

If the list fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this list.

Which is what I remembered: if the array you pass to toArray(T[] a) can't fit everything in the list, a new array is allocated. Plainly, there are 256 elements in the list, which cannot fit in an array of size 0, therefore a new array must be allocated inside the method, right?

So is that note incorrect? Or is there something else it means?

like image 747
Tom Tresansky Avatar asked Jan 11 '13 14:01

Tom Tresansky


2 Answers

Plainly, there are 256 elements in the list, which cannot fit in an array of size 0, therefore a new array must be allocated inside the method, right?

yes.


You can use

 private static final Update NO_UPDATES = { }

 lu.toArray(NO_UPDATES);

however this will should only help if you expect the list to be typically 0 length.

Generally, I would the same approach as fge

 lu.toArray(new Update[lu.size()]);

In your specific case you know the size in advance so you can do

Update[] updates = new Update[256];
String text = "";
final Update.Builder ub = new Update.Builder();
final Author a = new Author("Tallulah");

long now = System.currentTimeMillis();
for (int i=0; i<updates.length; i++) 
  updates[i] = ub.author(a).updateText(text += 'X').createTime(now++).build();

Collections.shuffle(Arrays.asList(updates));
like image 126
Peter Lawrey Avatar answered Sep 27 '22 19:09

Peter Lawrey


Going off of @Andreas comment on the question, I think it is a typo, and should say:

Pass zero-sized array, safe allocation.

Because if you passed nothing to the method, you'll end up calling the List#toArray() no-argument overload!

This would return an Object[] (though it would contain nothing but Update instances) and would require changing the type of the updates variable, so the last line would become:

Object[] updates = lu.toArray();

And then every time you wanted to iterate over and use the elements in that array, you'd have to cast them to Update.

Supplying the array calls the List#toArray(T[] a) method, which returns a <T> T[]. This array is reified to know it is an array of Update instances.

So supplying an empty array of Updates results in an Update[] coming back from the toArray call, not an Object[]. This is a much more type-safe allocation! The word "save" in the note must be a typo!

...this consumed way too much mental effort. Will post link to this in the book's forums so they can correct it.

like image 26
Tom Tresansky Avatar answered Sep 27 '22 19:09

Tom Tresansky