Post-transform and the standard Collectors

Brian Goetz brian.goetz at
Tue May 28 15:23:22 PDT 2013

Adding the ability to have a post-transform function raises some questions about how the standard collectors should change to accomodate them.  These fall into two categories:
 - Should we?
 - How?

For collectors like toStringBuilder, we can now collect to a String and not expose the intermediate StringBuilder type.  This is both closer to what the user wants and allows for better implementation hiding:

 static Collector<String, ?, String> toStringBuilder() { ... }

Of course, now the name is wrong.  So it would need a new name.  (Ditto for toStringJoiner.)  

It also makes sense to have a new combinator that can attach a post-transform to an existing Collector (name is just a placeholder): 

  <T, I, R> Collector<T, I, R> transforming(Function<I, R>, Collector<T, ?, I>)

A harder question is how much to introduce immutability.  For example, one negative of the current toList() collector is that the returned list is sometimes, but not always, immutable.  It would be nice to be able to commit to something.  We could easily make it immutable with a post-transform of Collections::immutableList.  At first, this seems a no-brainer.  But after more thought, it's definitely a "should we?"

Consider how this plays as a downstream collector.  The simplest form of groupingBy -- groupingBy(f) -- expands to groupingBy(f, toList()).  If we made toList always return an immutable List, then we would have to apply the post-transform to every value of the resulting map, likely via a (sequential) Map.replaceAll on the simplest groupingBy operation, even when the user didn't care about immutability.  Making every groupingBy user pay for this seems like a lot.  (Alternately, the default toList() could still return an immutable list, but the default groupingBy could use a different downstream collector.)  

One option is to have mutable and immutable versions of every Collection/Map-bearing Collector.  But this is a 2x explosion of Collectors, after we did so much work to pare back the size of the Collector set.   Another is to have combinators for adding immutability to Collection, List, Set, and Map.   Then an immutable groupingBy would be:

  collect(asImmutableMap(groupingBy(f, asImmutableList(toList()))));

Wordy, but not terrible, and probably better than imposing the costs on everyone?  

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