programming5 min read

Tutorial: Learn Groovy from Scratch (2026)

Tutorial: Learn Groovy from Scratch (2026)

Published:  |  Category: Programming  |  Reading time: ~15 min
Tutorial: Learn Groovy from Scratch (2026)

Groovy is a dynamic language for the JVM that feels like a streamlined, concise version of Java. I have used it for scripting, build automation (Gradle), web development (Grails), and testing. Groovy integrates seamlessly with Java — you can mix Groovy and Java files in the same project.

What makes Groovy practical is that it lowers ceremony without sacrificing access to the Java ecosystem. Closures, builders, and optional typing make common patterns significantly less verbose.

Closures

Closures are Groovy's executable code blocks. They can capture variables, be passed to methods, and used as lambdas. it is the implicit parameter for single-argument closures. Closures support currying, composition, and delegation. They are the foundation of Groovy's collection methods (each, collect, findAll).

def greet = { name -> println "Hello, $name" }
greet('Alice')

def square = { it * it }
assert [1,2,3].collect(square) == [1, 4, 9]

def filterAndMap = { list, pred, transform ->
  list.findAll(pred).collect(transform)
}

def result = filterAndMap(1..10, { it % 2 == 0 }, { it * 10 })
assert result == [20, 40, 60, 80, 100]

// Closure delegation
class Config {
  String host
  int port
}

def config = new Config()
def configure = { host = 'localhost'; port = 8080 }
configure.delegate = config
configure()
assert config.host == 'localhost'

Builders

Builders construct nested structures with DSL-like syntax. MarkupBuilder generates XML/HTML. JsonBuilder creates JSON. SwingBuilder builds UI. BuilderSupport lets you create custom builders. The builder pattern uses Groovy's methodMissing and closure delegation to create natural hierarchical syntax.

import groovy.xml.MarkupBuilder

def writer = new StringWriter()
def html = new MarkupBuilder(writer)

html.html {
  head {
    title 'My Page'
  }
  body {
    h1 'Welcome'
    p(class: 'intro') {
      mkp.yield 'Hello, '
      b 'Groovy'
    }
    ul {
      ['A', 'B', 'C'].each { li it }
    }
  }
}
println writer.toString()

import groovy.json.JsonBuilder

def json = new JsonBuilder()
json.user {
  name 'Alice'
  age 30
  roles ['admin', 'user']
}
println json.toPrettyString()

Groovy Truth

Groovy extends boolean evaluation: null is false, empty collections are false, empty strings are false, zero is true (unlike other languages). This makes conditionals concise. The Elvis operator ?: provides default values. The safe navigation operator ?. avoids NPEs by short-circuiting on null.

def name = null
assert !name

def list = []
assert !list

def str = ''
assert !str

def num = 42
assert num // nonzero is true

// Elvis operator
def display = name ?: 'default'
assert display == 'default'

// Safe navigation
def user = [address: [city: 'NYC']]
assert user?.address?.city == 'NYC'

def missing = null
assert missing?.anything == null

GDK (Groovy JDK)

The Groovy Development Kit extends the JDK with useful methods. String gets reverse(), tokenize(), and interpolation. Collections gain each(), collect(), findAll(), groupBy(), and inject(). File and I/O operations are simplified. Range literals (1..10) are first-class objects.

// String extensions
def s = 'Hello, World!'
assert s.reverse() == '!dlroW ,olleH'
assert s[0..4] == 'Hello'
assert "sum: ${1 + 2}" == 'sum: 3'

// Collection extensions
def items = [4, 2, 3, 1, 5]
assert items.sort() == [1, 2, 3, 4, 5]
assert items.findAll { it > 2 } == [4, 3, 5]
assert items.collect { it * 2 } == [8, 4, 6, 2, 10]

// File operations
def text = new File('data.txt').text
new File('out.txt') << 'appended'

// Ranges
assert (1..5).sum() == 15

Grails Framework

Grails uses Convention over Configuration for web development. Controllers handle requests, services contain business logic, domain classes map to database tables. GSP (Groovy Server Pages) handles views. Grails uses GORM for ORM (built on Hibernate). Scaffolding generates CRUD views automatically. The plugin system extends functionality.

// Domain class
grails create-domain-class Book

class Book {
  String title
  String author
  Date published
  
  static constraints = {
    title blank: false, size: 1..255
    author blank: false
  }
}

// Controller
grails create-controller Book

class BookController {
  def index() {
    params.max = Math.min(params.max ?: 10, 100)
    respond Book.list(params),
      model: [bookCount: Book.count()]
  }
  
  def show(Long id) {
    respond Book.get(id)
  }
  
  def save() {
    def book = new Book(params)
    if (book.save()) {
      redirect action: 'show', id: book.id
    } else {
      render view: 'create', model: [book: book]
    }
  }
}

Metaprogramming

Groovy supports runtime metaprogramming. Expando creates dynamic objects. MetaClass lets you add methods to any class at runtime. methodMissing catches undefined method calls. propertyMissing handles undefined properties. Categories add methods to classes within a scope. The @Delegate annotation implements the decorator pattern.

// Dynamic methods
String.metaClass.greet = { -> "Hello, $delegate" }
assert 'Alice'.greet() == 'Hello, Alice'

// Expando
def dyno = new Expando()
dyno.name = 'dynamic'
dyno.say = { -> "I am $name" }
assert dyno.say() == 'I am dynamic'

// methodMissing
class DynamicHandler {
  def handlers = [:]
  def methodMissing(String name, args) {
    def handler = handlers[name]
    handler ? handler(*args) : "unknown: $name"
  }
}

def dh = new DynamicHandler()
dh.handlers['foo'] = { a, b -> a + b }
assert dh.foo(1, 2) == 3

Frequently Asked Questions

Groovy vs Kotlin?

Groovy is dynamically typed by default (with optional static compilation), has closures with delegation, and builders. Kotlin is statically typed with coroutines. Groovy excels for scripting and DSLs; Kotlin for type-safe application code.

What is the difference between def and typed variables?

def makes Groovy use dynamic typing (resolved at runtime). Typed variables (@CompileStatic) are checked at compile time, matching Java's type safety.

How does Groovy handle null safety?

The safe navigation operator (?.) short-circuits on null. The Elvis operator (?:) provides defaults. Groovy does not have compile-time null safety like Kotlin.

What is Grails?

A full-stack web framework inspired by Ruby on Rails. It uses convention-over-configuration, GORM for persistence, and GSP for templating. Runs on the JVM.

Originally published on Ayodhyyya. Last updated June 1, 2026.