RFR(s): 8060192: Add default method Collection.toArray(generator)
Stuart Marks
stuart.marks at oracle.com
Fri Jun 15 01:02:04 UTC 2018
Hi all,
I wanted to restart review of the changeset for bug JDK-8060192 [1]. The latest
webrev is here: [2].
The previous review was from December 2017: [3]. The only difference between the
current changeset and the previous one is the removal of the overriding
implementations (see explanation below). Much of the discussion in the previous
review thread was around performance and the shape of the API.
# Performance
I previously had done some benchmarking on this and reported the results: [4].
(I've recently re-done the benchmarks and conclusions are essentially the same.)
The upshot is that implementations that use Arrays.copyOf() are the fastest,
probably because it's an intrinsic. It can avoid zero-filling the freshly
allocated array because it knows the entire array contents will be overwritten.
This is true regardless of what the public API looks like. The default
implementation calls generator.apply(0) to get a zero-length array and then
simply calls toArray(T[]). This goes through the Arrays.copyOf() fast path, so
it's essentially the same speed as toArray(new T[0]).
The overrides I had previously provided in specific implementation classes like
ArrayList actually are slower, because the allocation of the array is done
separately from filling it. This necessitates the extra zero-filling step. Thus,
I've removed the overrides.
# API Shape
There was some discussion about whether it would be preferable to have a Class
parameter as a type token for the array component type or the array type itself,
instead of using an IntFunction generator. Most of this boils down to what
people are comfortable with. However, there are a few points that make the
generator function approach preferable.
One point in favor of using a generator is that Stream already has a similar
toArray(generator) method.
Comparing this to the type token alternatives, for simple tasks like converting
Collection<String> to String[], things are about equal:
toArray(String[]::new)
toArray(String.class)
toArray(String[].class)
However, things are hairier if the element type of the collection is generic,
such as Collection<List<String>>. The result type is a generic array
List<String>[]. Using class literals or array constructor references will
necessitate using an unchecked cast, because none of these can be used to
represent a generic type.
However, it's possible to use a method reference to provide a properly generic
IntFunction. This would enable the toArray(generator) method to be used without
any unchecked casts. (The method it refers to might need have an unchecked cast
within it, though.) Such a method could also be reused for the corresponding
Stream.toArray(generator) method.
For these reasons I'd like to proceed with adding toArray(generator) API.
Thanks,
s'marks
[1] https://bugs.openjdk.java.net/browse/JDK-8060192
[2] http://cr.openjdk.java.net/~smarks/reviews/8060192/webrev.3/
[3] http://mail.openjdk.java.net/pipermail/core-libs-dev/2017-December/050325.html
[4] http://mail.openjdk.java.net/pipermail/core-libs-dev/2017-December/050585.html
More information about the core-libs-dev
mailing list