问题
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?
回答1:
According to a findbugs report, this is the most efficient:
String[] addressesArray = addresses.toArray(new String[addresses.size()]);
I believe them ;)
回答2:
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).
回答3:
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.
回答4:
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.
回答5:
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.)
回答6:
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.
来源:https://stackoverflow.com/questions/727627/what-to-pass-to-the-arrays-instance-method-toarrayt-a-method