In Java 8, there is Stream.collect
which allows aggregations on collections. In Kotlin, this does not exist in the same way, other than maybe as a collection of extension functions in the stdlib. But it isn't clear what the equivalences are for different use cases.
For example, at the top of the JavaDoc for Collectors
are examples written for Java 8, and when porting them to Kolin you can't use the Java 8 classes when on a different JDK version, so likely they should be written differently.
In terms of resources online showing examples of Kotlin collections, they are typically trivial and don't really compare to the same use cases. What are good examples that really match the cases such as documented for Java 8 Stream.collect
? The list there is:
- Accumulate names into a List
- Accumulate names into a TreeSet
- Convert elements to strings and concatenate them, separated by commas
- Compute sum of salaries of employee
- Group employees by department
- Compute sum of salaries by department
- Partition students into passing and failing
With details in the JavaDoc linked above.
Note: this question is intentionally written and answered by the author (Self-Answered Questions), so that the idiomatic answers to commonly asked Kotlin topics are present in SO. Also to clarify some really old answers written for alphas of Kotlin that are not accurate for current-day Kotlin.
Best Answer
There are functions in the Kotlin stdlib for average, count, distinct,filtering, finding, grouping, joining, mapping, min, max, partitioning, slicing, sorting, summing, to/from arrays, to/from lists, to/from maps, union, co-iteration, all the functional paradigms, and more. So you can use those to create little 1-liners and there is no need to use the more complicated syntax of Java 8.
I think the only thing missing from the built-in Java 8Collectors
class is summarization (but in another answer to this question is a simple solution).One thing missing from both is batching by count, which is seen in another Stack Overflow answer and has a simple answer as well. Another interesting case is this one also from Stack Overflow: Idiomatic way to spilt sequence into three lists using Kotlin. And if you want to create something likeStream.collect
for another purpose, see Custom Stream.collect in KotlinEDIT 11.08.2017: Chunked/windowed collection operations were added in kotlin 1.2 M2, see https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/
It is always good to explore the API Reference for kotlin.collections as a whole before creating new functions that might already exist there.
Here are some conversions from Java 8
Stream.collect
examples to the equivalent in Kotlin:Accumulate names into a List
Convert elements to strings and concatenate them, separated by commas
Compute sum of salaries of employee
Group employees by department
Compute sum of salaries by department
Partition students into passing and failing
Names of male members
Group names of members in roster by gender
Filter a list to another list
Finding shortest string a list
Counting items in a list after filter is applied
and on it goes... In all cases, no special fold, reduce, or other functionality was required to mimic
Stream.collect
. If you have further use cases, add them in comments and we can see!About laziness
If you want to lazy process a chain, you can convert to a
Sequence
usingasSequence()
before the chain. At the end of the chain of functions, you usually end up with aSequence
as well. Then you can usetoList()
,toSet()
,toMap()
or some other function to materialize theSequence
at the end.Why are there no Types?!?
You will notice the Kotlin examples do not specify the types. This is because Kotlin has full type inference and is completely type safe at compile time. More so than Java because it also has nullable types and can help prevent the dreaded NPE. So this in Kotlin:
is the same as:
Because Kotlin knows what
people
is, and thatpeople.age
isInt
therefore the filter expression only allows comparison to anInt
, and thatpeople.name
is aString
therefore themap
step produces aList<String>
(readonlyList
ofString
).Now, if
people
were possiblynull
, as-in aList<People>?
then:Returns a
List<String>?
that would need to be null checked (or use one of the other Kotlin operators for nullable values, see this Kotlin idiomatic way to deal with nullable values and also Idiomatic way of handling nullable or empty list in Kotlin)See also: