Refactor of Collector interface

Kevin Bourrillion kevinb at google.com
Fri Feb 8 08:43:35 PST 2013


Oh, it's about performance. I see that now.

Well, if it's possible to just tell us, "Hey, a group-by of 10000 elements
used to incur N bytes of garbage and now causes only M," that's very easy
to know how to react to.


On Fri, Feb 8, 2013 at 8:36 AM, Brian Goetz <brian.goetz at oracle.com> wrote:

> Your subjective sense is accurate, which is why I brought this up.  This
> may be an example where is better to depart from the traditional approach.
>
> To your question, it depends what you mean by "purely to do with an
> implementor."  Collector *users* are going to be burdened with the
> performance consequences of multiple layers of wrapping/conversion.
>
> The implementation used to be full of alternation between:
>
> interface Foo<T,U> {
>     U transform(T t);
> }
>
> class FooAdapter<T,U> {
>     FooAdapter(Function<T,U> lambda) { ... }
>
>     U transform(T t) { return lambda.apply(t); }
> }
>
> and
>
> Function<T,U> parentTransformer = foo::transform;
>
> and back again, introducing layers of wrapping even when the function is
> not changing across layers.
>
>
>
>
> On 2/8/2013 11:22 AM, Kevin Bourrillion wrote:
>
>> My subjective sense of good Java API design very strongly prefers the
>> "before" picture here, which I see as a lot more "Java-like", so I'm
>> taking a closer look.
>>
>> I assume that the trade-offs we're weighing here are purely to do with
>> what it's like to be a Collector implementor, correct?
>>
>>
>> On Fri, Feb 8, 2013 at 7:25 AM, Brian Goetz <brian.goetz at oracle.com
>> <mailto:brian.goetz at oracle.com**>> wrote:
>>
>>     FYI: In a recent refactoring, I changed:
>>
>>     public interface Collector<T, R> {
>>          R makeResult();
>>          void accumulate(R result, T value);
>>          R combine(R result, R other);
>>     }
>>
>>     to
>>
>>     public interface Collector<T, R> {
>>          Supplier<R> resultSupplier();
>>          BiConsumer<R, T> accumulator();
>>          BinaryOperator<R> combiner();
>>     }
>>
>>     Basically, this is a refactoring from typical interface to
>>     tuple-of-lambdas.  What I found was that there was a lot of
>>     adaptation going on, where something would start out as a lambda,
>>     we'd wrap it with a Collector whose method invoked the lambda, then
>>     take a method reference to that wrapping method and then later wrap
>>     that with another Collector, etc.  By keeping access to the
>>     functions directly, the Collectors code got simpler and less wrappy,
>>     since a lot of functions could just be passed right through without
>>     wrapping.  And a lot of stupid adapter classes went away.
>>
>>     While clearly we don't want all interfaces to evolve this way, this
>>     is one where *all* the many layers of manipulations are effectively
>>     function composition, and exposing the function-ness made that
>>     cleaner and more performant.  So while I don't feel completely
>>     super-great about it, I think its enough of a win to keep.
>>
>>
>>
>>
>> --
>> Kevin Bourrillion | Java Librarian | Google, Inc. |kevinb at google.com
>> <mailto:kevinb at google.com>
>>
>


-- 
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/lambda-libs-spec-experts/attachments/20130208/11e1cb43/attachment.html 


More information about the lambda-libs-spec-experts mailing list