Having some background with FP from Scala I really don't like Groovy's names for collections methods. Given that and some architectural choices made above, I found using a Java 8 streams API (plus java.util.Optional) in Groovy code an appealing solution.
Until I hit this:
def finalCollection = [ 'some', 'items', 'really', 'not', 'important' ].stream()
.map { aMethodReturningOptional(it) } //map String to Optional<Item>
.flatMap { it.map(Stream.&of).orElseGet(Stream.&empty) } //convert to Stream<Item>
.collect() //Groovy's collect, not stream's!
Note it works only in Groovy 2+ - treating closure as lambda.
What bothers me is the last line of the example code. Groovy translates the call to the DefaultGroovyMethods.collect()
instead of Stream.collect()
that I originally wanted to use. Of course then the last line would be:
.collect(Collectors.toList()) //Should call Java collect, but it doesn't
It seems counter-intuitive to me, that some extension method is called instead of native, 'built-in' method of the class.
How can I rewrite the example so the Stream.collect()
method would be called?
UPDATE: After some more fiddling, I've found out what problem I had originally. I wrote .collect{Collectors.toList()}
(note curly braces), which of course called Groovy method, not Java. Note to self: remember to quadruple-check before posting...
Groovy 2.5. 0 adds several methods to make working with Java 8 Streams more Groovy. First of all the methods toList and toSet are added to the Stream class. These methods will convert the stream to a List and Set using the Stream.
A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. The features of Java stream are – A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.
You obtain a stream from a collection by calling the stream() method of the given collection. Here is an example of obtaining a stream from a collection: List<String> items = new ArrayList<String>(); items.
Using Collectors.toList()
you can get what you want to do:
import java.util.stream.*
class Item {
final String name
Item(name) {
this.name = name
}
@Override
String toString() {
name
}
}
def itemize(String name) {
Optional.of(new Item(name))
}
def finalCollection = [ 'some', 'items', 'really', 'not', 'important' ].stream()
.map { itemize(it) } //map String to Optional<Item>
.flatMap { it.map(Stream.&of).orElseGet(Stream.&empty) } //convert to Stream<Item>
.collect (Collectors.toList())
assert 'java.util.ArrayList' == finalCollection.class.name
assert finalCollection.collect { it.name } == ['some', 'items', 'really', 'not', 'important']
Anyway, with groovy 2.4.5 the above is working also with
def finalCollection = [ 'some', 'items', 'really', 'not', 'important' ].stream()
.map { itemize(it) } //map String to Optional<Item>
.flatMap { it.map(Stream.&of).orElseGet(Stream.&empty) } //convert to Stream<Item>
.collect()
that uses groovy's collect:
transforming each item into a new value using Closure.IDENTITY as a transformer, basically returning a list of items copied from the original object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With