Search

Dark theme | Light theme
Showing posts with label GroovyGoodness:GDK. Show all posts
Showing posts with label GroovyGoodness:GDK. Show all posts

September 17, 2025

Groovy Goodness: Getting Extension And BaseName For File And Path

Groovy 5 adds the extension methods getExtension and getBaseName to the File and Path classes. You can invoke them as properties for a File and Path objects. Also the asBoolean method is added. This mean you can use a File or Path instance in a boolean context. If the underlying file exists true is returned and false otherwise.

September 12, 2025

Groovy Goodness: Accessing Regular Expression Named Groups By Name

Groovy (and Java) support using names for groups in regular expressions. The name of the group is defined using the syntax ?<name> where name must be replaced with the actual group name. This is very useful, because you can use the group name to access the value that is captured by the defined regular expression in a java.util.regex.Matcher object. Groovy supports for a long time accessing a group using the index operator. Since Groovy 5 you can use the name of the group to access the value as well. You can specify the name between square brackets ([<name>]) or use the name as property.

August 30, 2025

Groovy Goodness: Use Range With subList Method

Groovy is known for exending standard Java classes with extra methods or extra arguments for existing methods. Since Groovy 5 you can use a range as argument for the List.subList method. The range is used to determine the begin and end index of the original List instance to return.

April 4, 2023

Groovy Goodness: Using Subscript Operator With Multiple Fields On Date Related Objects

Since Groovy 4.0.5 we can use a subscript operator that accepts multiple fields on a java.util.Date and java.util.Calendar objects. And Groovy 4.0.6 extended this subscript operator to any java.time.TemporalAccessor instance. Before these Groovy version we could already use the subscript operator, but we could provide only one field we wanted to access. In a previous post we already have seen this. But now we can use multiple fields to get their values with one statement. We simply define the fields we want as arguments to the subscript operator. Under the hood the subscript operator is implemented by a getAt method that is added as an extension to the Date, Calendar and TemporalAccess classes. The return type is java.util.List and we can combine this with the multiple assignment support in Groovy. In other languages it is also called destructurizing. With multiple assignments we can assign the values from a java.util.List directly to variables.

In the following example we see several usages of the subscript operator with multiple fields on Date, Calendar and LocalDateTime objects:

import java.time.LocalDateTime
import java.time.Month
import static java.time.temporal.ChronoField.*
import static java.time.temporal.IsoFields.*

// Create a Date instance.
def date = new Date().parse('yyyy/MM/dd', '1973/07/09')

// Groovy adds the subscript operator for multiple
// fields to the Date class.
def output = date[Calendar.DATE, Calendar.MONTH, Calendar.YEAR]
assert output == [9, 6, 1973]

// The result is a list and we can destructurize it
// to assign values to variables (also called multiple assignments).
def (day, month, year) = date[Calendar.DATE, Calendar.MONTH, Calendar.YEAR]

assert "$day-${month + 1}-$year" == "9-7-1973"


// Create a Calendar instance.
def calendar = date.toCalendar()

// The subscript operator supporting multiple fields
// is also added to the Calendar class.
def (calDay, calMonth, calYear) = calendar[Calendar.DATE, Calendar.MONTH, Calendar.YEAR]

assert "Time to celebrate on $calDay-${calMonth + 1}" == "Time to celebrate on 9-7"


// Create a LocalDateTime instance
def birthDateTime = LocalDateTime.of(1973, Month.JULY, 9, 6, 30, 0);

// Groovy adds the subscript operator with multiple fields
// on any TemporalAccessor instance.
def (dayOfWeek, dayOfYear, quarter, week) = birthDateTime[DAY_OF_WEEK, DAY_OF_YEAR, QUARTER_OF_YEAR, WEEK_OF_WEEK_BASED_YEAR]

assert "Born in week $week on day $dayOfWeek" == "Born in week 28 on day 1"
assert quarter == 3
assert dayOfYear == 190

def (hour, minute) = birthDateTime[HOUR_OF_DAY, MINUTE_OF_HOUR]

assert "Live started at $hour:$minute" == "Live started at 6:30"

Written with Groovy 4.0.11.

June 28, 2022

Groovy Goodness: Using The Switch Expression

In a previous (old) post we learned how Groovy supports different classifiers for a switch case statement. Since Groovy 4 we can use switch also as an expression. This means the switch statement returns a value without having to use return. Instead of using a colon (:) and break we use the -> notation for a case. We specify the value that the switch expressions returns after ->. When we need a code block we simply put the code between curly braces ({...}).

In the following example we use the switch expression with different case statements:

def testSwitch(val) {
    switch (val) {
        case 52 -> 'Number value match'
        case "Groovy 4" -> 'String value match'
        case ~/^Switch.*Groovy$/ -> 'Pattern match'
        case BigInteger -> 'Class isInstance'
        case 60..90 -> 'Range contains'
        case [21, 'test', 9.12] -> 'List contains'
        case 42.056 -> 'Object equals'
        case { it instanceof Integer && it < 50 } -> 'Closure boolean'
        case [groovy: 'Rocks!', version: '1.7.6'] -> "Map contains key '$val'"
        default -> 'Default'
    } 
}

assert testSwitch(52) == 'Number value match'
assert testSwitch("Groovy 4") == 'String value match'
assert testSwitch("Switch to Groovy") == 'Pattern match'
assert testSwitch(42G) == 'Class isInstance'
assert testSwitch(70) == 'Range contains'
assert testSwitch('test') == 'List contains'
assert testSwitch(42.056) == 'Object equals'
assert testSwitch(20) == 'Closure boolean' 
assert testSwitch('groovy') == "Map contains key 'groovy'"
assert testSwitch('default') == 'Default'

Written with Groovy 4.0.3.

March 10, 2020

Groovy Goodness: Taking Or Dropping Number Of Characters From A String

Groovy adds a lot of methods to the Java String class. For example we can use the take method to get a certain number of characters from the start of a string value. With the drop method we remove a given number of characters from the start of the string. In Groovy 3 we can now also take and drop a certain number of characters from the end of a string using the methods takeRight and dropRight.

In the following example we see how we can use the methods:

def s = "Groovy rocks!"

// Drop first 7 characters.
assert s.drop(7) == "rocks!"

// Drop last 7 characters.
assert s.dropRight(7) == "Groovy"


// Take first 6 characters.
assert s.take(6) == "Groovy"

// Take last 6 characters.
assert s.takeRight(6) == "rocks!"

Written with Groovy 3.0.2.

February 19, 2020

Groovy Goodness: Shuffle List or Array

In Java we can use Collections.shuffle method to randomly reorder items in a list. Groovy 3.0.0 adds the shuffle and shuffled methods to a List or array directly. The implementation delegates to Collections.shuffle. The shuffle method will reorder the original list, so there is a side effect using this method. Or we can use the shuffled method that will return a copy of the original list where the items are randomly ordered.

In the next example we use both methods to randomly order lists:

def signs = (2..10) + ['J', 'Q', 'K', 'A']
def symbols = ['♣', '♦', '♥', '♠']

// Create list as [♣2, ♦2, ♥2, ♠2, ..., ♣A, ♦A, ♥A, ♠A] 
def cards = [symbols, signs].combinations().collect { it.join() }

// Store original cards list.
def deck = cards.asImmutable()

// We should have 52 cards.
assert cards.size() == 52

// Let's shuffle the cards.
// Notice this will change the cards list.
cards.shuffle()
 
assert cards.every { card -> deck.contains(card) }

println cards.take(5) // Possible output: [♣6, ♠A,  ♥Q, ♦Q, ♠5]

// We can use our own Random object for shuffling.
cards.shuffle(new Random(42))

assert cards.every { card -> deck.contains(card) }

println cards.take(5)  // Possible output: [♦5, ♦2, ♦3, ♣7, ♦J]


// Store first 5 cards.
def hand = cards.take(5)

// Using shuffled we get a new list 
// with items in random order. 
// The original list is not changed.
def shuffledCards = cards.shuffled()

assert shuffledCards.size() == cards.size()
assert shuffledCards.every { card -> cards.contains(card) }

// Original list has not changed.
assert hand == cards.take(5)

println shuffledCards.take(5) // Possible output: [♣4, ♠2, ♠6, ♥Q, ♦4]

// We can pass our own Random object.
def randomizer = new Random(42)
def randomCards = cards.shuffled(randomizer)

assert randomCards.size() == cards.size()
assert randomCards.every { card -> cards.contains(card) }

println randomCards.take(5) // Possible output: [♥5, ♠6, ♠8, ♣3, ♠4]

Written with Groovy 3.0.0.

January 12, 2020

Groovy Goodness: Transform Elements While Flattening

We can use the flatten method in Groovy to flatten a collection that contains other collections into a single collection with all elements. We can pass a closure as extra argument to the flatten method to transform each element that is flattened. The argument of the closure is the element from the original collection.

In the following example we first use the flatten method without a closure argument. Then we pass a closure argument and transform the element:

def list = [1, [2, 3], [[4]]]

// Simple flatten the nested collections.
assert list.flatten() == [1, 2, 3, 4]

// We can use a closure to transform
// the elements in the resulting collection.
assert list.flatten { it * 2 } == [2, 4, 6, 8]

Written with Groovy 2.5.7.

June 21, 2018

Groovy Goodness: Unmodifiable Collections

When we wanted to create collections in Groovy that were unmodifiable we could use asImmutable. Since Groovy 2.5.0 we can also use the asUnmodifiable method on collections. The method can be applied on all Collection types including Map.

In the following example we use asUnmodifiable on a List and Map:

import static groovy.test.GroovyAssert.shouldFail

// Create List that is unmodifiable.
def list = ['Groovy', 'Gradle', 'Asciidoctor', 'Micronaut'].asUnmodifiable()

shouldFail(UnsupportedOperationException) {
    // We cannot add new items.
    list << 'Java'
}
    
shouldFail(UnsupportedOperationException) {
    // We cannot change items.
    list[0] = 'Java'
}


// Create Map that is unmodifiable.
def data = [name: 'Messages from mrhaki', subject: 'Gr8 stuff'].asUnmodifiable()

shouldFail(UnsupportedOperationException) {
    // We cannot add a new key.
    data.subject = 'Dev subjects'
}
    
shouldFail(UnsupportedOperationException) {
    // We cannot change the value of a key.
    data.blog = true
}

Written with Groovy 2.5.0.

June 13, 2018

Groovy Goodness: Remove Last Item From List Using RemoveLast Method (And Pop/Push Methods Reimplemented)

Versions of Groovy before 2.5.0 implemented pop and push methods for the List class for items at the end of a List object. The pop method removed the last item of a List and push added a item to the List. Groovy 2.5.0 reimplemented the methods so they now work on the first item of a List instance. To remove an item from the end of the list we can use the newly added method removeLast.

In the following example Groovy code we use the removeLast and add methods to remove and add items to the end of the list. And with the pop and push methods we remove and add items to the beginnen of the list:

def list = ['Groovy', 'is', 'great!']
 
// Remove last item from list
// with removeLast().
assert list.removeLast() == 'great!'
assert list == ['Groovy', 'is']
 
// Remove last item which is now 'is'.
list.removeLast()
 
// Add new item to end of the list.
list.add 'rocks!'
 
assert list.join(' ') == 'Groovy rocks!'


/* IMPORTANT */
/* pop() and push() implementations has changed */
/* in Groovy 2.5.0. They now work on the first */
/* item in a List instead of the last. */

// Using pop() we remove the first item
// of a List.
assert list.pop() == 'Groovy'

// And with push we add item to 
// beginning of a List.
list.push 'Spock'

assert list.join(' ') == 'Spock rocks!'

Written with Groovy 2.5.0.

Groovy Goodness: Truncate And Round BigDecimal Values

Groovy 2.5.0 adds round and truncate methods to the BigDecimal class. These methods were already available on Double and Float classes. The methods can take an argument to denote the number of decimals the rounding or truncating must be applied to.

In the following example we see the methods with and without arguments:

def bigDecimal = 42.576135

// Groovy uses BigDecimal for decimal 
// numbers by default.
assert bigDecimal.class.name == 'java.math.BigDecimal'

assert bigDecimal.round() == 43
assert bigDecimal.round(2) == 42.58

assert bigDecimal.trunc() == 42
assert bigDecimal.trunc(2) == 42.57

Written with Groovy 2.5.0.

June 12, 2018

Groovy Goodness: Intersect Collections With Custom Comparator

In a previous post we learned about the intersect method added to collections in Groovy. Since Groovy 2.5.0 we can supply a custom Comparator to the intersect method to define our own rules for the intersection.

In the following example we first apply the intersect method with the default Comparator. Then we create a new Comparator using a closure where we check if the value is in both collections and if the value starts with the letter M:

def stuff = ['Groovy', 'Gradle', 'Grails', 'Spock', 'Micronaut', 'Ratpack'] as Set
def micro = ['Ratpack', 'Micronaut', 'SpringBoot', 'Microservice']

// Using default comparator to get values
// that are in both collections.
assert stuff.intersect(micro) == ['Ratpack', 'Micronaut'] as Set
assert micro.intersect(stuff) == ['Micronaut', 'Ratpack']

// Comparator to check if value is in
// both collection and starts with a 'M'.
def microName = { a, b -> 
    def comp = a <=> b
    comp == 0 ? a[0] == 'M' ? 0 : -1 : comp
} as Comparator

// This time we use the Comparator and
// end up with all elements in both
// collections that start with a 'M'.
assert stuff.intersect(micro, microName) == ['Micronaut'] as Set
assert micro.intersect(stuff, microName) == ['Micronaut']

Written with Groovy 2.5.0.

Groovy Goodness: Easy Object Creation With Tap Method

Groovy 2.5.0 adds the tap method to all objects and changes the method signature of the with method. In a previous post we already learned about the with method. In Groovy 2.5.0 we can add an extra boolean argument to the with method. If the value is false (is default) the with method must return the same value as what the closure invocation returns. If the value is true the object instance on which the with method is invoked is returned. The new tap method is an alias for with(true), so it will always return the object instance.

In the first example we use the tap method to create a new Sample object and set property values and invoke methods of the Sample class:

/** 
 * Sample class with some properties
 * and a method.
 */
class Sample {
    
    String username, email
    
    List<String> labels = []
    
    void addLabel(value) { 
        labels << value 
    }
    
}

// Use tap method to create instance of 
// Sample and set properties and invoke methods. 
def sample = 
        new Sample().tap {
            assert delegate.class.name == 'Sample'
            
            username = 'mrhaki'
            email = 'email@host.com'
            addLabel 'Groovy'
            addLabel 'Gradle'
            
            // We use tap, an alias for with(true), 
            // so the delegate of the closure, 
            // the Sample object, is returned.
        }

assert sample.labels == ['Groovy', 'Gradle']
assert sample.username == 'mrhaki'
assert sample.email == 'email@host.com'

In the following example we use the with method to demonstrate the differences for several invocations using different argument values:

/** 
 * Sample class with some properties
 * and a method.
 */
class Sample {
    
    String username, email
    
    List<String> labels = []
    
    void addLabel(value) { 
        labels << value 
    }
    
}

// Use with method to create instance of 
// Sample and set properties and invoke methods. 
def sample1 = 
        new Sample().with {
            assert delegate.class.name == 'Sample'

            username = 'mrhaki'
            email = 'email@host.com'
            addLabel 'Groovy'
            addLabel 'Gradle'   
        }
       
// With method returns the result 
// from the closure. In the previous
// case the return result is null,
// because the last statement addLabel
// is used as return value. addLabel has
// return type void.
assert !sample1


// Use with method to create instance of 
// Sample and set properties and invoke methods. 
def sample2 = 
        new Sample().with {
            assert delegate.class.name == 'Sample'

            username = 'mrhaki'
            email = 'email@host.com'
            addLabel 'Groovy'
            addLabel 'Gradle'
            
            // Explicitly return delegate of
            // closure, which is the Sample object.
            return delegate
        }

assert sample2.labels == ['Groovy', 'Gradle']
assert sample2.username == 'mrhaki'
assert sample2.email == 'email@host.com'


// Use with method to create instance of 
// Sample and set properties and invoke methods. 
def sample3 = 
        new Sample().with(true) {
            assert delegate.class.name == 'Sample'

            username = 'mrhaki'
            email = 'email@host.com'
            addLabel 'Groovy'
            addLabel 'Gradle'
            
            // We use with(true), so the 
            // delegate of the closure, the Sample
            // object, is returned.
        }

assert sample3.labels == ['Groovy', 'Gradle']
assert sample3.username == 'mrhaki'
assert sample3.email == 'email@host.com'

A good use case for using the with method is to transform an object to another type using values from the object. In the next example we use values from a Sample objects to create a new String:

/** 
 * Sample class with some properties
 * and a method.
 */
class Sample {
    
    String username, email
    
    List<String> labels = []
    
    void addLabel(value) { 
        labels << value 
    }
    
}

def sample = 
        new Sample().tap {
            username = 'mrhaki'
            email = 'email@host.com'
            addLabel 'Groovy'
            addLabel 'Gradle'
        }

// The with method can be very useful to
// transform object to another type using
// values from the object.
def user = sample.with { "$username likes ${labels.join(', ')}." }

assert user == 'mrhaki likes Groovy, Gradle.'

Written with Groovy 2.5.0.

Groovy Goodness: Where Is My Class?

Groovy 2.5.0 makes it possible to get the location of a Class file by adding the method getLocation to the Class class. If the Class is part of the JDK the location returned is null, but otherwise we get the location of the JAR file or source file (if available) with the Class file.

In the following example we get the location for the internal JDK String class and the Groovy utility class ConfigSlurper:

// Internal JDK class location is null.
assert String.location == null


// Import ConfigSlurper with alias.
import groovy.util.ConfigSlurper as ConfigReader

// Location of Groovy JAR file.
def groovyJarFile = 'file:/Users/mrhaki/.sdkman/candidates/groovy/2.5.0/lib/groovy-2.5.0.jar'.toURL()   

// ConfigSlurper is located in the Groovy JAR file.
assert ConfigSlurper.location == groovyJarFile

// Works also for aliased class.
assert ConfigReader.location == groovyJarFile                                                 

Written with Groovy 2.5.0.

Groovy Goodness: Calculate MD5 And SHA Hash Values

Groovy adds a lot of useful methods to the String class. Since Groovy 2.5.0 we can even calculate MD5 and SHA hash values using the methods md5 and digest. The md5 method create a hash value using the MD5 algorithm. The digest method accepts the name of the algorithm as value. These values are dependent on the available algorithms on our Java platform. For example the algorithms MD2, MD5, SHA-1, SHA-256, SHA-384 and SHA-512 are by default available.

In the next example we use the md5 and digest methods on a String value:

def value = 'IamASecret'

def md5 = value.md5()

// We can provide hash algorithm with digest method.
def md2 = value.digest('MD2')
def sha1 = value.digest('SHA-1')
def sha256 = value.digest('SHA-256')

assert md5 == 'a5f3147c32785421718513f38a20ca44'
assert md2 == '832cbe3966e186194b1203c00ef47488'
assert sha1 == '52ebfed118e0a411e9d9cbd60636fc9dea718928'
assert sha256 == '4f5e3d486d1fd6c822a81aa0b93d884a2a44daf2eb69ac779a91bc76de512cbe'

Written with Groovy 2.5.0.

June 11, 2018

Groovy Goodness: Base64 URL and Filename Safe Encoding

Groovy supported Base64 encoding for a long time. Since Groovy 2.5.0 we can also use Base64 URL and Filename Safe encoding to encode a byte array with the method encodeBase64Url. The result is a Writable object. We can invoke the toString method on the Writable object to get a String value. An encoded String value can be decoded using the same encoding with the method decodeBase64Url that is added to the String class.

In the following example Groovy code we encode and decode a byte array:

import static java.nio.charset.StandardCharsets.UTF_8 

def message = 'Groovy rocks!'

// Get bytes array for String using UTF8.
def messageBytes = message.getBytes(UTF_8)

// Encode using Base64 URL and Filename encoding.
def messageBase64Url = messageBytes.encodeBase64Url().toString()

// Encode using Base64 URL and Filename encoding with padding.
def messageBase64UrlPad = messageBytes.encodeBase64Url(true).toString()

assert messageBase64Url == 'R3Jvb3Z5IHJvY2tzIQ'
assert messageBase64UrlPad == 'R3Jvb3Z5IHJvY2tzIQ=='

// Decode the String values.
assert new String(messageBase64Url.decodeBase64Url()) == 'Groovy rocks!'
assert new String(messageBase64UrlPad.decodeBase64Url()) == 'Groovy rocks!'

Written with Groovy 2.5.0.

Groovy Goodness: Java 8 Stream Enhancements

Groovy 2.5.0 adds several methods to make working with Java 8 Streams more Groovy. First of all the methods toList and toSet are added to the Stream class. These methods will convert the stream to a List and Set using the Stream.collect method with Collectors.toList and Collectors.toSet as argument. Furthermore we can convert any array object to a Stream using the stream method that is added to all array objects.

In the following example we use the support of converting an array to a Stream and then getting a List and Set from the stream:

def sample = ['Groovy', 'Gradle', 'Grails', 'Spock'] as String[]

def result = sample.stream()  // Use stream() on array objects
                   .filter { s -> s.startsWith('Gr') } 
                   .map { s -> s.toUpperCase() }
                   .toList()  // toList() added to Stream by Groovy
                   
assert result == ['GROOVY', 'GRADLE', 'GRAILS']


def numbers = [1, 2, 3, 1, 4, 2, 5, 6] as int[]

def even = numbers.stream()  // Use stream() on array objects
                  .filter { n -> n % 2 == 0 }
                  .toSet()  // toSet() added to Stream 
                  
assert even == [2, 4, 6] as Set

Written with Groovy 2.5.0.

June 7, 2018

Groovy Goodness: Use Optional In Conditional Context

In Groovy 2.5.0 we can use a Java 8 Optional object in a conditional context. When an Optional object has a value the value is coerced to true and when empty the value is false.

assert !Optional.empty()
assert !Optional.ofNullable(null)
assert Optional.of('Groovy rocks!')

Written with Groovy 2.5.0.

Groovy Goodness: Use Range By Method To Set Steps Between Numbers

Groovy has support for defining ranges in the language. When we define a range of numbers the steps between the values in the range is 1 by default. We can change the step size using the step method. This method accepts a int value with a new step size. The result is a List object with the values. Since Groovy 2.5.0 the by method is added to ranges with numbers. The by method accepts also decimal numbers and the result of the method is a NumberRange object instead of a List.

In the following example Groovy script we first define a range with int values. We use the by method to change the step size using both an int value and BigDecimal value. We also use the by method for a range of BigDecimal numbers:

// Define range with int values.
def ints = 1..10

assert ints.from == 1
assert ints.to == 10
assert ints == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
assert ints.class.name == 'groovy.lang.IntRange'

// Use by method to set steps
// between int values in range.
// The results is a new range.
def intsBy = ints.by(3)

assert intsBy.from == 1
assert intsBy.to == 10
assert intsBy == [1, 4, 7, 10]
assert intsBy.class.name == 'groovy.lang.NumberRange'

// Use step method to set steps
// between int values in range.
// The range is now converted to a List.
def intsStep = ints.step(3)

assert intsStep == [1, 4, 7, 10]
assert intsStep.class.name == 'java.util.ArrayList'

// Use by method to set step size to 0.9.
def intsBy2 = ints.by(0.9)

assert intsBy2.from == 1
assert intsBy2.to == 10
assert intsBy2 == [1, 1.9, 2.8, 3.7, 4.6, 5.5, 6.4, 7.3, 8.2, 9.1, 10.0]
assert intsBy2.class.name == 'groovy.lang.NumberRange'


// Define range with BigDecimal numbers.
def numbers = 1.0..4.5

assert numbers.from == 1.0
assert numbers.to == 4.5
assert numbers == [1.0, 2.0, 3.0, 4.0]
assert numbers.class.name == 'groovy.lang.NumberRange'

// Use by method to set step size
// between numbers to 0.5.
def numbersBy = numbers.by(0.5)

assert numbersBy.from == 1.0
assert numbersBy.to == 4.5
assert numbersBy == [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]
assert numbersBy.class.name == 'groovy.lang.NumberRange'

// We cannot use the step method to set
// step size to 0.5,
// because the step method only accepts
// int values as argument.
try {
    numbers.step(0.5)
} catch (MissingMethodException e) {
    assert e.message.contains('Possible solutions: step(int), step(int, groovy.lang.Closure)')
}

Written with Groovy 2.5.0.

October 17, 2017

Groovy Goodness: Make Sure Closeable Objects Are Closed Using withCloseable Method

If a class implements the Closeable interface Groovy adds the withCloseable method to the class. The withCloseable method has a closure as argument. The code in the closure is executed and then the implementation of the close method of the Closeable interface is invoked. The Closeable object is passed as argument to the closure, so we can refer to it inside the closure.

In the following example we have two objects that implement the Closeable interface. By using withCloseable we know for sure the close method is invoked after all the code in the closure is executed:

@Grab(group='org.apache.httpcomponents', module='httpclient', version='4.5.3')
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.client.methods.HttpGet

// HttpClientBuilder.create().build() returns a CloseableHttpClient
// that implements the Closeable interface. Therefore we can use
// the withCloseable method to make sure the client is closed
// after the closure code is executed. 
HttpClientBuilder.create().build().withCloseable { client ->
    final request = new HttpGet('http://www.mrhaki.com')

    // The execute method returns a CloseableHttpResponse object
    // that implements the Closeable interface. We can use
    // withCloseable method to make sure the response is closed
    // after the closure code is executed.
    client.execute(request).withCloseable { response ->
        assert response.statusLine.statusCode == 200
    }
}

Written with Groovy 2.4.12.