ArrayFactory SAM type / toArray
brian.goetz at oracle.com
Wed Sep 19 14:15:07 PDT 2012
> Why passing a lambda that will be called in the body of the toArray ?
> It's simpler to directly pass the array.
No, that's what the existing unfortunate toArray(T) does. Things that
are wrong with it:
- If you get the size wrong, it has to reallocate.
- If it reallocates, it has to do it reflectively.
- It is inherently racy.
To see the racy part, consider an implementation like SynchronizedList.
If the user does:
Foo array = c.toArray(new Foo[c.size()]);
where c is a synchronized list, we acquire the lock, compute the size,
release the lock, and pass the array into toArray, which will have to
allocate again (reflectively) if the size has changed. Whereas an
implementation of toArray(ArrayFactory) can create the array once at the
proper size while ensuring no concurrent modifications.
So, comparing the status quo toArray(T) with the proposed (low
quality) default version:
- Worst case is identical
- Best case is better in that allocation is not done reflectively
And a non-crappy overriden implementation can be better still (eliminate
Arguably the proposed approach also provides a better separation of
concerns; having the client allocate the array for the library seems
questionable. (Arguably it is even better from an API design
perspective to pass a class literal rather than a lambda, but that gets
us back into reflection.)
> What problem are you trying solve?
I think the above should explain, but in a nutshell the problem is: the
two existing precedents for toArray as done in Collection are both
unfortunate, and I'd rather not propagate them blindly into Streams.
They're probably the best we could have done without lambdas in the
language, but with lambdas, a better alternative arises -- let the
library create the array with a factory provided by the caller. I would
like to offer a better version of toArray for Streams, and possibly
consider retrofitting onto Collection.
More information about the lambda-libs-spec-observers