Java 8 Lambdas vs Groovy Closures Compactness: Grouping And Summing

 Groovy, Java   3 Minutes

Java 8 is featuring lambdas, which are similar to a construction Groovy has already for some time: closures.

In Groovy we could already do this:

def list = ['a', 'b', 'c']
print list.collect { it.toUpperCase() }
// [A, B, C]

where { it.toUpperCase() } is the closure.

In Java 8 we can achieve the same functionality now in a concise way.

list.stream().map( s -> s.toUpperCase() )

Although you could argue that with proper use of the new Stream API, bulk operations and method references, at least the intent of a piece of code is conveyed more clearly now – Java’s verboseness can still cause sore eyes.

Here are some other examples.

Some Groovy animals
1
2
3
4
5
6
7
8
9
10
11
class Animal {
    String name
    BigDecimal price
    String farmer
    String toString() { name }
}
 
def animals = []
animals << new Animal(name: "Buttercup", price: 2, farmer: "john")
animals << new Animal(name: "Carmella", price: 5, farmer: "dick")
animals << new Animal(name: "Cinnamon", price: 2, farmer: "dick")

Example 1: Summing the total price of all animals

Groovy
1
2
assert 9 == animals.sum { it.price }
// or animals.price.sum()

What Groovy you see here:

Java 8
1
2
3
4
5
6
Optional<BigDecimal> sum =
    animals.
        stream().
        map(Animal::getPrice).
        reduce((l, r) -> l.add(r));
assert BigDecimal.valueOf(9) == sum.get();

What Java you see here:

Example 2: Grouping all animals by farmer

Groovy
1
2
def animalsByFarmer = animals.groupBy { it.farmer }
// [john:[Buttercup], dick:[Carmella, Cinnamon]]
Java 8
1
2
3
4
5
6
Map<String, List<Animal>> animalsByFarmer =
    animals
        .stream()
        .collect(
            Collectors.groupingBy(Animal::getFarmer));
// {dick=[Carmella, Cinnamon], john=[Buttercup]}

Example 3: Summing the total price of all animals grouped by farmer

Groovy
1
2
3
4
5
def totalPriceByFarmer =
    animals
        .groupBy { it.farmer }
        .collectEntries { k, v -> [k, v.price.sum()] }
// [john:2, dick:7]

What Groovy you see here:

Java 8
1
2
3
4
5
6
7
8
9
10
11
Map<String, BigDecimal> totalPriceByFarmer =
    animals
        .stream()
        .collect(
            Collectors.groupingBy(
                Animal::getFarmer,
                Collectors.reducing(
                    BigDecimal.ZERO,
                    Animal::getPrice,
                    BigDecimal::add)));
// {dick=7, john=2}

This Java code again yields the same results. Since IDE’s, Eclipse at least, don’t format this properly, you’ll have to indent these kinds of constructions for readability a bit yourself.