Learn Groovy - Exception Handling & Debugging
Episode 7 of 23

Learn Groovy - Exception Handling & Debugging

This episode covers exception handling in Groovy: try/catch/finally, multi-catch, and resource management. You will also create custom exceptions, handle runtime errors, and practice techniques for debugging Groovy scripts and inspecting runtime values.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

A program that runs smoothly without errors is the exception, not the rule. Episode 7 equips you with the ability to handle errors gracefully and find the root cause when a program fails.

You'll learn try/catch/finally, multi-catch, resource management, custom exceptions, and techniques for debugging Groovy scripts and inspecting runtime values.

Exception Handling Basics

Try/Catch/Finally

Groovy's try/catch/finally structure is identical to Java's. The finally block always executes, whether or not an exception occurs:

Basic try/catch/finally
try {
    def hasil = 10 / 0
    println hasil
} catch (ArithmeticException e) {
    println "Terjadi pembagian dengan nol: ${e.message}"
} finally {
    println "Blok finally selalu dijalankan"
}

try { def hasil = 10 / 0 } throws an ArithmeticException at runtime, caught by the catch block, and then finally still runs. The finally block is typically used to clean up resources like database connections.

Multi-Catch

Groovy supports multi-catch in a single block, using a pipe between exception types:

Multi-catch exception
def bacaAngka(String teks) {
    try {
        return Integer.parseInt(teks)
    } catch (NumberFormatException | NullPointerException e) {
        println "Input tidak valid: ${e.message}"
        return null
    }
}
 
println bacaAngka("abc")

catch (NumberFormatException | NullPointerException e) catches two kinds of exceptions in one block — syntax that only became available in Java 7 and is fully supported by Groovy.

Catch Without a Type

Generic catch
try {
    throw new RuntimeException("Gagal memproses")
} catch (e) {
    println "Error: ${e.message}"
}

This pattern is useful at the outermost layer of an application, for example to log before the program stops.

Resource Management

withCloseable

Groovy provides a safer pattern than manually closing resources. withCloseable ensures the resource is closed automatically after the block finishes:

Automatic resource management
import java.nio.file.Files
import java.nio.file.Paths
 
def path = Paths.get("/tmp/contoh.txt")
Files.newOutputStream(path).withCloseable { stream ->
    stream.write("Halo".bytes)
}
 
println "File berhasil ditulis"

Files.newOutputStream(path).withCloseable { stream -> ... } opens a stream, executes the closure, then closes the stream automatically. This pattern is equivalent to Java's try-with-resources without the boilerplate.

Resource Best Practices

  • Use withCloseable or withReader for all I/O.
  • Don't swallow exceptions with an empty catch.
  • Release resources as soon as possible, don't wait for the garbage collector.
  • Separate business logic from error handling.

Custom Exceptions

Creating Your Own Exception

Custom exception
class SaldoTidakCukupException extends RuntimeException {
    SaldoTidakCukupException(String pesan) {
        super(pesan)
    }
}
 
def tarikSaldo(int saldo, int jumlah) {
    if (jumlah > saldo) {
        throw new SaldoTidakCukupException("Saldo tidak cukup: ${saldo}")
    }
    return saldo - jumlah
}
 
try {
    tarikSaldo(100, 150)
} catch (SaldoTidakCukupException e) {
    println "Gagal: ${e.message}"
}

class SaldoTidakCukupException extends RuntimeException creates a custom exception, and throw new SaldoTidakCukupException("...") throws it to be caught specifically.

When to Create a Custom Exception

Custom exceptions are useful when one kind of error must be handled differently in many places, or when the error needs to carry additional data such as a transaction id. Avoid overcreating custom exceptions; use Java's built-in exceptions if they're sufficient.

Debugging Groovy Scripts

Printing Runtime Values

The simplest way to inspect a runtime value is println. For more detail, inspect displays the object's literal representation:

Inspect runtime values
def data = [nama: "Arman", nilai: [80, 90]]
println data.inspect()
println "Tipe data: ${data.getClass().getSimpleName()}"

data.inspect() produces a literal representation that can be re-evaluated — very useful when debugging data structures. Meanwhile, getClass().getSimpleName() shows the actual dynamic type.

Debugging with an IDE

If you use IntelliJ IDEA, add a breakpoint directly in the .groovy script and run it in debug mode:

  • Breakpoint: pauses execution at a specific line.
  • Expression evaluation: run code while the debugger is paused.
  • Watch variables: monitor variable value changes.

Capturing the Stack Trace

Print the stack trace
try {
    new File("/tidak/ada/file.txt").text
} catch (Exception e) {
    e.printStackTrace()
}

e.printStackTrace() prints the chain of method calls up to the point of error. Read the stack trace from the top line, because that's the location closest to the actual cause.

Common Errors and Their Solutions

  • MissingMethodException: calling a method that doesn't exist, usually a typo or a mismatched type.
  • ClassCastException: forcing an incompatible type.
  • NullPointerException: using a null object without safe navigation.

For the first error, check the method spelling and make sure the closure uses the correct parameter names. For the last error, apply the ?. and ?: operators we already learned in episode 4.

Closing

Episode 7 completed your error-handling capabilities: try/catch/finally, multi-catch, resource management with withCloseable, custom exceptions, and script debugging techniques with println, inspect, and stack traces.

The key takeaways:

  • finally always runs, whether or not an exception occurs.
  • Multi-catch with a pipe catches several exception types at once.
  • withCloseable closes resources automatically without boilerplate.
  • Custom exceptions clarify the kind of error on an API.
  • inspect() displays an object's literal representation while debugging.
  • Read the stack trace from the top line to find the error's cause.

In episode 8 next, we'll discuss scripting and command-line automation — writing Groovy scripts for automation tasks, parsing command-line arguments and environment variables, as well as file handling, text processing, and log output.