7

If you have an instance of a Collection, say something like:

Collection<String> addresses = new ArrayList<String>();

Which were to then be populated with a bunch of values, which is the "best" way, if any, to make use of the toArray() method without requiring a type cast?

String[] addressesArray = addresses.toArray(new String[] {});
String[] addressesArray = addresses.toArray(new String[0]);
String[] addressesArray = addresses.toArray(new String[addresses.size()]);
String[] addressesArray = addresses.toArray(new String[addresses.size() + 5]);

Is there any semantic difference between the first two? Is the third most efficient? Is the fourth less efficient than the third?

Craig Otis
  • 31,257
  • 32
  • 136
  • 234

6 Answers6

7

For my money

String[] addressesArray = addresses.toArray(new String[0]);

is simplest, least error-prone and therefore "best". It also has the advantage that the same code works for concurrent/synchronized collections. You would have to be in some really low-level, heavily used code for the negligible performance difference to make any difference.

Often you see an empty array assigned to a static final to avoid the allocation on every execution. Apparently, it turns out that the performance can drop due to that "optimisation" (allocation really are very fast).

Update: Turn out this is faster than using a sized array. http://shipilev.net/blog/2016/arrays-wisdom-ancients/ tl;dr: The reflection is of the trivial kind not involving slow method lookup, and zeroing of the array can be dropped if it can be determined that all of the elements will be written (or array becomes unreachable).

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • 2
    +1 for noticing the concurrency issue. I've faced that issue in my code once: http://github.com/orfjackal/dimdwarf/blob/0d1a0897821a4e0e557a1390a7252a8580d2ec95/dimdwarf-core/src/main/java/net/orfjackal/dimdwarf/scheduler/TaskThreadPool.java#L111-116 – Esko Luontola Apr 08 '09 at 14:27
  • Though normally I use the "addresses.toArray(new String[addresses.size()])" approach. – Esko Luontola Apr 08 '09 at 14:31
  • 1
    This is both simpler AND faster! http://shipilev.net/blog/2016/arrays-wisdom-ancients/ – Luna Feb 19 '16 at 20:21
  • @RossAllan Yes, I saw that. Subject to change and implementation, of course. Unlikely to ever be a problem. – Tom Hawtin - tackline Feb 20 '16 at 01:31
5

According to a findbugs report, this is the most efficient:

String[] addressesArray = addresses.toArray(new String[addresses.size()]);

I believe them ;)

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
HMM
  • 2,987
  • 1
  • 20
  • 30
  • 5
    This is incorrect, according to an article by @AlekseyShipilev http://shipilev.net/blog/2016/arrays-wisdom-ancients/ – Luna Feb 19 '16 at 20:21
2

If you choose not to believe others, or just want to check for yourself, you can review the source for java.util.ArrayList (posting the source probably violates some license, I'm glad I'm just linking to it). You also get a copy of all the source code when you download Sun's JDK).

After reviewing the source code for <T> T[] toArray(T[] a); it is apparent that:

String[] addressesArray = addresses.toArray(new String[addresses.size()]);

is the fastest way to do it.

Obviously you can't always take the time to read and understand the source code, and sometimes the best performing option is not always obvious, but for simpler methods, it can be very informative to read the source.

Grant Wagner
  • 25,263
  • 7
  • 54
  • 64
1

This is mostly of theoretical interest, but if the list is empty often, you can reuse a zero-length array:

private static final String[] EMPTY_STRING_ARRAY = {};
...
String[] addressesArray = addresses.toArray(EMPTY_STRING_ARRAY);

Since zero-length arrays are immutable (unlike non-zero-length arrays), they are OK to store away and reuse.

gustafc
  • 28,465
  • 7
  • 73
  • 99
0

This is documented in javadoc of the List interface:

If the list fits in the specified array with room to spare (i.e., the array has more elements than the list), the element in the array immediately following the end of the list is set to null. (This is useful in determining the length of the list only if the caller knows that the list does not contain any null elements.)

andri
  • 11,171
  • 2
  • 38
  • 49
  • It makes sense that if the size of the ArrayList is 5, and you pass toArray() a new String array of size 10 then it would be resized, but I still don't know which is more or less proper/efficient. – Craig Otis Apr 07 '09 at 21:25
  • It does not resize the array, it simply sets the element past the end of the list to null. – Grant Wagner Apr 07 '09 at 21:38
0

You're doing effectively the same thing with the first two statements.

The third is most efficient, for if your elements will not fit into the array, a new array is created for you.

Steve Reed
  • 2,481
  • 2
  • 20
  • 20