Skip to content

Groovy Guide — Closures: Functional Building Blocks

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Groovy Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

Groovy closures are reusable code blocks that can access variables from their surrounding scope, accept parameters, be assigned to variables, and passed to methods for Functional Programming.

What You'll Learn

  • Closure syntax and creation
  • Parameters and implicit variable 'it'
  • Closure scope and delegation
  • Functional operations on collections
  • Currying and composition

Why It Matters

Closures enable functional programming patterns in Groovy, making collection operations concise and code more reusable. Durga Antivirus Pro uses closures for rule processing.

Real-World Use

Data transformation pipelines, event handlers, collection processing, and DSL construction all use closures.

flowchart LR
    A["Closures"] --> B["Syntax"]
    B --> C["Parameters"]
    C --> D["Collections"]
    D --> E["Delegation"]
    A:::current --> B
    style A fill:#2563eb,stroke:#2563eb,color:#fff
    style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b

Closure Basics

def greet = { println "Hello!" }
greet()  // "Hello!"

def square = { it * it }
println square(5)  // 25

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

Parameters

// Implicit parameter 'it'
def doubleIt = { it * 2 }
doubleIt(5)  // 10

// Named parameters
def multiply = { int a, int b -> a * b }

// Default values
def greet = { String name = "World" -> "Hello, $name!" }

// Varargs
def sumAll = { int... nums -> nums.sum() }

Closures with Collections

def numbers = [1, 2, 3, 4, 5]

def doubled = numbers.collect { it * 2 }
println doubled  // [2, 4, 6, 8, 10]

def evens = numbers.findAll { it % 2 == 0 }
println evens  // [2, 4]

def sum = numbers.inject(0) { acc, val -> acc + val }
println sum  // 15

Closure Scope

def outer = "Hello"

def createClosure() {
    def inner = "World"
    return { println "$outer $inner" }
}

def closure = createClosure()
closure()  // "Hello World"

// Closures capture variables by reference

Closure Delegation

class Handler {
    def process(String data) {
        println "Processing: $data"
    }
}

def closure = { process("data") }
closure.delegate = new Handler()
closure()  // "Processing: data"

// Closures can change their delegate
class Logger {
    def log(String msg) { println "LOG: $msg" }
}

def logClosure = { log("test") }
logClosure.delegate = new Logger()
logClosure()

Currying

def multiply = { a, b -> a * b }
def double = multiply.curry(2)
def triple = multiply.curry(3)

println double(5)  // 10
println triple(5)  // 15

// Right curry
def divideBase10 = multiply.curry(10)
// Left curry (second param)
def half = multiply.rcurry(0.5)

Closure Composition

def compose = { Closure f, Closure g ->
    { it -> f(g(it)) }
}

def double = { it * 2 }
def square = { it * it }

def doubleThenSquare = compose(square, double)
println doubleThenSquare(3)  // (3*2)^2 = 36

// Or use << (before) and >> (after) operators
def pipeline = double >> square
println pipeline(3)  // 36

Common Mistakes

1. Overusing implicit 'it'

For complex closures, name parameters explicitly for clarity.

2. Modifying captured variables

Closures capture references. Modifying shared mutable state can cause unexpected behavior.

3. Confusing delegate with owner

The delegate is configurable. The owner is the enclosing object. They can differ.

4. Closure identity

Each closure literal creates a new instance. Cache closures if creating many.

5. Return statement behavior

Return inside a closure returns from the closure, not the enclosing method.

Practice Questions

1. What is 'it' in a closure? The implicit parameter name for single-parameter closures when no explicit parameter is declared.

2. How do you curry a closure? Use the curry() method to fix one or more parameters, returning a new closure with fewer parameters.

3. What is delegation in closures? The delegate property determines which object receives method calls made within the closure.

Challenge: Create a closure-based pipeline that processes a list of numbers through filter, map, and reduce.

FAQ

{{< faq question="Are closures like lambdas in Java?" >} Groovy closures are more powerful than Java Lambdas. They support currying, delegation, and have access to surrounding scope. {{< /faq >}}

{{< faq question="Can closures be serialized?" >} Yes, if all captured variables are serializable. Use for distributed processing. {{< /faq >}}

{{< faq question="What is closure Recursion?" >} A closure calling itself. Use the variable name or the this reference inside the closure. {{< /faq >}}

{{< faq question="How do closures handle performance?" >} Closures have some overhead vs methods. For tight loops, use methods instead. For flexibility, closures are fine. {{< /faq >}}

{{< faq question="Can closures be passed to Java code?" >} Yes. Groovy closures implement the appropriate functional interfaces when used with Java APIs. {{< /faq >}}

Mini Project

Build a data processing pipeline with closures:

def pipeline = { data ->
    data.findAll { it > 0 }
        .collect { it * 2 }
        .inject(0) { sum, val -> sum + val }
}

def numbers = [-3, -1, 0, 2, 4, 6]
println pipeline(numbers)  // (2+4+6)*2 = 24

// Composable steps
def filterPositive = { it.findAll { it > 0 } }
def doubleValues = { it.collect { it * 2 } }
def sumValues = { it.sum() }

def composed = filterPositive >> doubleValues >> sumValues
println composed(numbers)

What's Next

Now that you understand closures, explore Groovy's string features.

Topic Description Link
Groovy Strings String operations {{< ref "05-strings" >}}
Groovy Collections Collection operations {{< ref "06-collections" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro