DevoxxUK Lambdas Lab
Brian Goetz
brian.goetz at oracle.com
Wed Apr 3 05:17:45 PDT 2013
> Some key points.
> The s -> s in the groupingBy looks weird, but is fairly logical.
Replace with Functions.identity().
But, there's almost certainly a better solution.
If the problem was computing word frequency, the reason it is horrible
is not the API :)
Map<String, Integer> m
= reader.lines()
.flatMap(s -> Arrays.stream(s.split(" ")))
.groupingBy(Functions.identity(),
reducing(s -> 1, Integer::sum)));
What this does is, instead of grouping to a List<String> and then
counting that, you make the downstream operation of the grouping be a
reduce instead of (effectively) a toList. Mapping each element to "1"
and then summing gets you count.
> The first and relatively easy step was producing a Map<String,
> List<String>>. I suspected that I needed to reduce to get the the list
> into a number, but it was completely non-obvious to me as to how to do
> that. The Collectors.reducing methods didn't seem to fit in anywhere,
> so I tried looking at the IntStatistics stuff. Again, it wasn't
> obvious as to whether they were relevant or how I'd use them. So,
> rather than ask for help, I decided to continue on and see if I could
> find any solution just by working with the APIs.
>
> As the collect-groupingBy has resulted in a Map, I started from there.
> The only way to get a stream was on the entrySet(), which wasn't
> really what I wanted but would have to do.
>
> The map() method to map the list to its size was easy in theory, but
> very verbose in practice.
>
> ACTION:
> Add a static method to Map.Entry:
> public static <K, V> Entry<K, V> of(K key, V value) {
> return new AbstractMap.SimpleImmutableEntry<K, V>(key, value);
> }
>
> I then wanted to convert the stream of Entry back to a Map. I assumed
> this would be easy. I spent lots of time going insane trying to find a
> way. Eventually, I got help to use the 3-arg form of collect(). Even
> then, working out what the 3 arguments meant and should be was complex
> and confusing. (I ended up writing the three arguments as separate
> lines, as I was getting inference errors and I had at that point low
> confidence in the inference engine. It turned out that the error was a
> separate problem, but I never tried putting the lines "back in", as
> the pain of using the API on that day was too much by that stage).
>
> ACTION:
> Add a much better way to convert a stream of Entry to a Map. Perhaps:
> .collect(Collectors.toMap(entry -> getKey(), entry -> entry.getValue()));
>
> The "correct" approach was apparantly this:
> Map<String, Integer> right = br.lines()
> .flatMap(s -> Arrays.stream(s.split(" ")))
> .collect(Collectors.groupingBy(
> s -> s, Collectors.reducing(s -> 1, Integer::sum)));
>
> This still seems pretty non-obvious. I guess its the stage of mapping
> the string to the number one which grates. (I can see what it does,
> but as I've said before, reducing is much more of a trick for non
> functional programmers to move to.)
>
> ACTION:
> Can there be some kind of reducingSum() method? It feels like a common
> use case, and might provide the source code for people to look at
> providing the example code for them to then learn and write more
> advanced reducers themselves.
>
>
> I'm sorry to say that my experience of the API wasn't that positive. I
> hope things can still be tweaked, or I worry about the code we're
> going to see.
>
> Stephen
>
>
> On 3 April 2013 09:12, Richard Warburton <richard.warburton at gmail.com> wrote:
>> *
>>
>> Hi,
>>
>> Last week at DevoxxUK we ran a brief lambdas hackday. People were
>> encouraged to focus on the collectors component of the API through setting
>> a few problems to solve. I appreciate its a bit late in the game as far as
>> API changes, but some of these issues are fixable through
>> documentation/improved compiler error changes rather than API changes.
>>
>> 1. No one complained about the move from “into(new ArrayList<Foo>());” ->
>> “collect(toList())” when you explained that the change had been made.
>> However, people didn’t naturally find Collectors.toList() and they did
>> express frustration around that. At least one request for an abbreviated
>> toList() method on a stream - more for findability/fluency reasons rather
>> than brevity of code.
>>
>> 2. ToIntFunction, ToDoubleFunction etc. are all usable with flatMap, but
>> the naming confused people as to why.
>>
>> 3. Several people requested a way to transform a boxed stream into an
>> unboxed stream. Its pretty easy to go the other way around, but there
>> didn’t seem to be any utility methods for making the boxed -> unboxed
>> transformation.
>>
>> 4. People found “groupingBy” to be a hard conceptual leap. We had set an
>> exercise where people were asked to count the frequency of words in a
>> document, in order to force them to use it.
>>
>> a. Quite a few people didn’t initially look for a function that collects a
>> stream into a map.
>>
>> b. When you suggest that they should look for that, they didn’t look for
>> something called “groupingBy”.
>>
>> c. They did get the concept once you bring up SQL. With hindsight I wished
>> I had enquired about how many people had used LINQ.
>>
>> d. People then didn’t grok that they needed to use the multiple argument
>> overload of groupingBy, with a reducingBy, in order to complete the task.
>> I suspect that this method needs more documentation examples in order to
>> be easily understandable by people.
>>
>> 5. People are beginning to get confused by old documentation on the
>> internet being out of date. I hadn’t seen this in previous hackdays. Even
>> an article in the latest Java Magazine is out of date due to the API moving
>> so much recently, and so is the official tutorial:
>> http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html.
>> Probably not a long term concern - but might be a concern for the first
>> few months.
>>
>> 6. If anyone else runs this kind of thing and they are a day-to-day eclipse
>> user, word of advice to make sure you know how to set the preferred JVM
>> location in netbeans and intellij before you run the event!
>>
>> Thanks to everyone that attended, and especially to Stuart Marks, Maurice
>> Naftalin, Graham Allan and John Oliver for helping out with running the lab.
>>
>> There’s a full link with code that people wrote and pasted at, and it also
>> contains some more comments by people:
>>
>> https://docs.google.com/document/d/1riMDt_JkAX74X30lHuOiSBjSxa7ifjxaynOA4LttOCk/edit
>>
>> regards,
>> *
>>
>> Richard Warburton
>>
>> http://insightfullogic.com
>> @RichardWarburto <http://twitter.com/richardwarburto>
>>
>
More information about the lambda-dev
mailing list