Corporate Training
Request Demo
Click me
Menu
Let's Talk
Request Demo

Tutorials

Closures and Lambda Expressions

14. Closures and Lambda Expressions

Closures and lambda expressions are powerful features in Groovy that allow you to define and use functions as first-class citizens. They enable you to write concise and expressive code, making your programs more readable and maintainable.

Closures:

In Groovy, a closure is a block of code that can take arguments, execute some logic, and return a result. Closures can capture and retain the context in which they are defined, including local variables and their values.

Creating Closures:

You can define closures using the '->' operator. Closures can take parameters, and their body is enclosed in curly braces '{}'.

Example: Defining a Closure
def greetingClosure = { name ->
    "Hello, $name!"
}

def result = greetingClosure("Alice")
println(result) // Output: Hello, Alice!
 

In this example, we define a closure 'greetingClosure' that takes a 'name' parameter and returns a greeting string.

Using Closures:

You can call closures just like regular functions.

Example: Using a Closure
def square = { num -> num * num }
def result = square(5)
println(result) // Output: 25
 

Here, we define a closure 'square'  that calculates the square of a number and then call it with the argument '5'.

Lambda Expressions:

Lambda expressions are a concise way to define closures, especially when they have a single parameter. In Groovy, you can use the '->'operator without the surrounding curly braces '{}' to create lambda expressions.

Example: Lambda Expression
def greet = name -> "Hello, $name!"
def result = greet("Bob")
println(result) // Output: Hello, Bob!
 

Lambda expressions are particularly useful when you need to pass a simple function as an argument to higher-order functions like 'each', 'collect', or 'findAll'.

Example: Using Lambda Expressions with'each'
def numbers = [1, 2, 3, 4, 5]
numbers.each { num ->
    println("Squared: ${num * num}")
}
 

Here, we use a lambda expression to specify the logic to apply to each element in the 'numbers' list when using the 'each' method.

Capturing Variables:

Closures can capture and retain the values of local variables from their surrounding scope, even if the closure is executed outside that scope.

Example: Capturing Variables in a Closure
def multiplier = 2
def timesTwo = { num -> num * multiplier }

def result1 = timesTwo(5)
println(result1) // Output: 10

multiplier = 3 // Modify the captured variable
def result2 = timesTwo(5)
println(result2) // Output: 15
 

In this example, the 'timesTwo' closure captures the 'multiplier' variable from its surrounding scope, even when it's executed after the 'multiplier' value changes.

Closure Composition:

You can compose closures by chaining them together to create more complex behavior.

Example: Composing Closures
def add = { a, b -> a + b }
def subtract = { a, b -> a - b }
def multiply = { a, b -> a * b }

def result = multiply(subtract(add(10, 5), 2), 3)
println(result) // Output: 39
 

Here, we compose closures 'add', 'subtract', and 'multiply' to perform a series of mathematical operations.

Conclusion:

Closures and lambda expressions are powerful tools in Groovy for defining and using functions as first-class citizens. They provide a concise and expressive way to write code, especially when working with collections, functional programming, and event handling. Understanding closures and lambda expressions is essential for writing clean, readable, and maintainable Groovy code.