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