Contents

A Groovy Alternative To Java 8 Streams and Collectors

Contents

I recently read this article over at DZone about using Java 8 Streams and Collectors to manipulate and perform calculations on a list of integers.  I don’t intend to start an argument over which language is better, but my immediate thought was that it would make a good blog post to show how one might perform these tasks in Groovy.  Collections in Groovy have long been a shining example of how Groovy enhances Java with convenience methods for common tasks.  Here’s a recreation of all the examples in the DZone post to show you how easy Groovy makes them:

Let’s throw together a List of 100 random integers:\

Random random = new Random()
List numbers = (0..100).collect { Math.abs(random.nextInt()) % 100 + 1 }
println 'Random list of 100 integers: ' + numbers

Determining the sum and average is quite simple:

println 'Computed sum of integers: ' + numbers.sum()
println 'Computed average of integers: ' + numbers.sum() / numbers.size()

Though, average isn’t a built in method.  So, let’s add it using metaprogramming instead:

List.metaClass.average = {
    return delegate.size() ? delegate.sum() / delegate.size() : 0
}
println 'Average using metaClass method: ' + numbers.average()

What about min/max?\

println 'Minimum number: ' + numbers.min()
println 'Maximum number: ' + numbers.max()

There’s no built in method to the DZone summarizingInt() example, but we can do either: \

println 'Summary: ' + [
        count  : numbers.size(),
        sum    : numbers.sum(),
        min    : numbers.min(),
        average: numbers.average(),
        max    : numbers.max(),
]

Or, again, add a method via metaprogramming:\

List.metaClass.summarizingInt = {
    return [
            count  : delegate.size(),
            sum    : delegate.sum() ?: 0,
            min    : delegate.min() ?: 0,
            average: delegate.average(),
            max    : delegate.max() ?: 0,
    ]
}

println 'Summary using metaClass: ' + numbers.summarizingInt()

def x = []
println 'Summary using metaClass on empty list: ' + x.summarizingInt()
// prints [count:0, sum:0, min:0, average:0, max:0]

Partitioning a list?  No problem in Groovy, just use groupBy:\

println 'Partitioning a List: ' + numbers.groupBy { it > 50 ? true : false }
// prints: [false:[16, 35, 34...], true:[96, 54, 58...]]

Here’s the full example in case you’d like to run them all yourself:\

Random random = new Random()
List numbers = (0..100).collect { Math.abs(random.nextInt()) % 100 + 1 }
println 'Random list of 100 integers: ' + numbers

println 'Computed sum of integers: ' + numbers.sum()
println 'Computed average of integers: ' + numbers.sum() / numbers.size()

List.metaClass.average = {
    return delegate.size() ? delegate.sum() / delegate.size() : 0
}
println 'Average using metaClass method: ' + numbers.average()

println 'Minimum number: ' + numbers.min()
println 'Maximum number: ' + numbers.max()

println 'Summary: ' + [
        count  : numbers.size(),
        sum    : numbers.sum(),
        min    : numbers.min(),
        average: numbers.average(),
        max    : numbers.max(),
]

List.metaClass.summarizingInt = {
    return [
            count  : delegate.size(),
            sum    : delegate.sum() ?: 0,
            min    : delegate.min() ?: 0,
            average: delegate.average(),
            max    : delegate.max() ?: 0,
    ]
}

println 'Summary using metaClass: ' + numbers.summarizingInt()

def x = []
println 'Summary using metaClass on empty list: ' + x.summarizingInt()
// prints [count:0, sum:0, min:0, average:0, max:0]

println 'Partitioning a List: ' + numbers.groupBy { it > 50 ? true : false }
// prints: [false:[16, 35, 34...], true:[96, 54, 58...]]

Image by romaneau from Pixabay