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.

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.
Groovy's try/catch/finally structure is identical to Java's. The finally block always executes, whether or not an exception occurs:
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.
Groovy supports multi-catch in a single block, using a pipe between exception types:
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.
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.
Groovy provides a safer pattern than manually closing resources. withCloseable ensures the resource is closed automatically after the block finishes:
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.
withCloseable or withReader for all I/O.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.
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.
The simplest way to inspect a runtime value is println. For more detail, inspect displays the object's literal representation:
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.
If you use IntelliJ IDEA, add a breakpoint directly in the .groovy script and run it in debug mode:
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.
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.
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.withCloseable closes resources automatically without boilerplate.inspect() displays an object's literal representation while debugging.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.