Hi Stuart,

On 06/15/18 03:02, Stuart Marks wrote:
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.

It's a little strange that the generator function is used to construct an empty array (at least in the default method, but overrides will likely do the same if they want to avoid pre-zeroing overhead) in order to just extract the array's type from it. Someone could reasonably expect the provided function to be called with the exact length of needed array. The Collection.toArray(T[]) at least gives user an option to actually fully use the provided array, if user provides the correct length. The argument about using (and re-using) a method so that a method reference can be passed to the method without any unchecked casts is equally true for any of the 3 alternatives shown - the method itself might need unchecked casts, but its usage not:

static List<String>[] array(int len)
static Class<List<String>> elementType()
static Class<List<String>[]> arrayType()


But I can see that you want to align the API with Stream.toArray, while still providing the optimal implementation. It's just that the API doesn't fit the usecase. The function approach makes more sense in the Stream API where it is explicitly explained that it may be used to construct arrays needed to hold intermediary results of partitioned parallel execution too, but in Collection API it is usually the case to just provide a copy of the underlying data structure in the most optimal way (without pre-zeroing overhead) and for that purpose, 2nd and 3rd alternatives are a better fit.

Suppose Stream took a different approach and used the 2nd or 3rd approach (which is universal). Would then Collection API also get the same method?


Regards, Peter

Reply via email to