Skip to content
Lesson 4 of 9

Step 1 of 5 · Reading · ~2 min

Learn

Collections and Closures

Closures are first-class blocks of code that keep access to the variables around them. They are written with { ... } and they turn up everywhere in Groovy:

def twice = { x -> x * 2 }
twice(5)                // 10

// implicit `it` for a single argument
def triple = { it * 3 }
triple(5)               // 15

// multi-arg
def add = { a, b -> a + b }
add(3, 4)               // 7

Name your closures carefully: double, int, float and friends are Java type keywords, so def double = { x -> x * 2 } is a compile error (Unexpected input: 'def double ='), not a closure.

Closures are why Gradle build scripts look the way they do — every task { } block is a closure being handed to a method.

Currying fixes the leading arguments and hands back a smaller closure:

def multiply = { a, b -> a * b }
def dbl = multiply.curry(2)
dbl(7)                  // 14

with runs a closure against an object as the receiver, so you can drop the repeated variable name:

new StringBuilder().with {
    append("Hello")
    append(", ")
    append("world")
    toString()          // the block's value is the last expression
}

The trap: an empty result is not zero

findAll returns a list, and sum() on an empty list returns null, not 0:

[1, 2].findAll { it > 10 }.sum()        // null, and prints as null
[1, 2].findAll { it > 10 }.sum() ?: 0   // 0

The Elvis operator ?: supplies the fallback. This exact case is one of the tests in the exercise below.

Your exercise

Filter a line of integers with a closure and total what survives. The mistake the grader catches is printing null for the line where nothing is greater than 10.

Up nextIf/Else and SwitchControl Flow

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…