Blog

Groovy | A Quick Glance

Key Takeaways

  • Groovy is a general-purpose JVM language, not just a scripting language. It can use Java classes and libraries.
  • List literals, closures, and collection methods make small tasks concise without requiring you to leave the Java ecosystem.
  • Groovy supports dynamic code, optional compile-time type checking with @TypeChecked, and static compilation with @CompileStatic.
  • Good reasons to learn it include Spock tests, Groovy-based Gradle builds, scripts, and existing Grails applications—not an assumption that every Java project needs another language.

Apache Groovy is a general-purpose programming language that runs on the Java Virtual Machine (JVM), combining Java-like syntax with dynamic features and optional static type checking. You can use it for scripts, compiled applications, or selected parts of a Java project. Its Java interoperability is a strength, but it doesn't make Groovy and Java interchangeable languages.

What Exactly Is Groovy?

Think of Groovy as another language for the JVM, rather than a replacement JVM or a Java library. It supports classes and object-oriented programming, while also offering closures—blocks of code you can pass around—and concise collection syntax.

The distinction between scripts and compiled applications is about how you develop and launch the code, not whether bytecode exists. Groovy scripts are compiled into classes; the groovy command runs them, while groovyc can produce class files ahead of time. Neither approach guarantees Java-equivalent performance.

Groovy vs Java: What Less Boilerplate Looks Like

Use JDK 21 and Groovy 5.1.3 for the following examples, with their command-line tools available on your path. The examples need no third-party libraries. Groovy 5.1 supports running on JDK 21; this is an example baseline, not a requirement to upgrade every existing Groovy project.

Both programs keep names with at least four characters and convert them to uppercase.

Java

// Names.java
import java.util.List;
import java.util.Locale;

public class Names {
    public static void main(String[] args) {
        List<String> names = List.of("Ada", "Grace", "Linus");
        List<String> result = names.stream()
                .filter(name -> name.length() >= 4)
                .map(name -> name.toUpperCase(Locale.ROOT))
                .toList();
        System.out.println(result);
    }
}

Groovy

// Names.groovy — Groovy source
 def names = ['Ada', 'Grace', 'Linus']
 def result = names.findAll { it.length() >= 4 }
                   .collect { it.toUpperCase(Locale.ROOT) }
 println result

findAll selects matching elements, collect transforms them, and it is the implicit parameter of a single-parameter closure. Both examples print [GRACE, LINUS]. Locale.ROOT makes the case conversion independent of the machine's default locale.

Save the files separately and run:

javac Names.java
java Names
groovy Names.groovy

Groovy's default imports include java.io.*, java.util.*, java.math.BigDecimal, and java.math.BigInteger. That's why the Groovy example can reference Locale without an explicit import; other APIs may still need one.

Dynamic Typing and Optional Static Checking

In dynamic Groovy, many method calls are resolved using the objects present at runtime. A method can accept an untyped parameter and call its length() method, but an unsuitable argument may fail only when that call executes. Writing an explicit type doesn't, by itself, enable static checking throughout the surrounding code.

ModeType checkingMethod dispatch
Dynamic GroovyMany invalid calls surface at runtimeDynamic resolution
@TypeCheckedChecks annotated code during compilationRetains dynamic dispatch
@CompileStaticIncludes compile-time type checkingStatically resolves calls in annotated code

Apply either annotation to a class or method. @CompileStatic already includes type checking, so you don't need to add @TypeChecked as well. Type inference still works: using def doesn't prevent the checker from inferring a local variable's type.

// Typing.groovy — run with: groovy Typing.groovy
import groovy.transform.CompileStatic

def dynamicLength(value) {
    value.length()
}

@CompileStatic
int checkedLength(String value) {
    // value.missingMethod() // Uncomment: compile-time error.
    value.length()
}

assert dynamicLength('Groovy') == 6
assert checkedLength('Groovy') == 6
// dynamicLength(42) // Uncomment: runtime MissingMethodException.

Static compilation is useful when you want earlier feedback and don't need runtime method customization. It can avoid dynamic-dispatch overhead, but it isn't a universal performance switch: it changes how calls are resolved and can conflict with dynamic behavior. Measure the actual workload rather than assuming shorter source means faster execution.

Advertisement

Closures and Groovy Java Interoperability

A closure can accept arguments, return a value, and reference variables from its surrounding scope. Closures fill many of the roles Java developers associate with lambdas, but Groovy also gives them an owner and a configurable delegate, which helps support domain-specific languages (DSLs): APIs written to read like a small language for a particular task.

Groovy can adapt a closure to a Java functional interface—an interface with one abstract method. This script calls Java's Function.apply and String.toUpperCase; it needs only Groovy and the JDK.

// Interop.groovy — run with: groovy Interop.groovy
import java.util.function.Function

Function<String, String> upper = { String value ->
    value.toUpperCase(Locale.ROOT)
}
assert upper.apply('groovy') == 'GROOVY'

If that callback style is unfamiliar, start with our guide to Java lambda expressions.

Why Use Groovy?

Testing Java Code with Spock

Spock is a concrete reason to use Groovy without rewriting your application. Its specifications organize tests into blocks such as given, when, and then, and support data-driven tests with a where block. That can make a matrix of inputs and expected results easier to review.

Adopt it because the test style helps your team—not because your production Java code is old. The same unit-testing principles still apply: isolate behavior, cover boundaries, and keep failures understandable.

Scripts and Gradle DSLs

Groovy is a reasonable fit for maintenance scripts that need existing Java libraries. You can keep the task small while reusing the classes your team already understands.

Gradle supports both Groovy DSL scripts, such as build.gradle, and Kotlin DSL scripts, such as build.gradle.kts. Learning Groovy helps when maintaining Groovy-based builds, but using Gradle doesn't require choosing Groovy for application code.

Web Applications with Grails

Grails is a Groovy-based web framework built on Spring Boot. As of October 17, 2026, its current release is Grails 8.0.0, which requires Java 21 and ships Groovy 5.1.3 in its standard dependency set. That is a specific, maintained ecosystem—not evidence that Grails or Groovy is the right choice for every new web application.

What Adding Groovy to a Java Project Costs

Groovy is compatible with a Java-centered workflow, but introducing it isn't dependency-free. Before adopting it, work through these decisions:

  • Choose compatible versions. Check the JDK, Groovy, build-tool, and framework requirements together. Our guide to choosing a Java version provides the broader runtime context.
  • Declare the project dependency. Groovy 4 and later use the org.apache.groovy dependency group. Gradle's embedded Groovy doesn't automatically supply your application's Groovy dependency.
  • Keep the scope intentional. Gradle uses implementation for production Groovy dependencies and testImplementation for test-only dependencies. Test-only Groovy needn't become an application runtime dependency.
  • Configure mixed-language compilation. Gradle's Groovy plugin supports joint compilation for Java and Groovy sources; its Groovy source directories can also contain Java files. Don't assume adding a compiler dependency alone establishes the source layout.
  • Align the test framework. Select a Spock variant compatible with your Groovy line rather than disabling its compatibility check.
  • Budget for maintenance. Decide who owns upgrades, how much dynamic behavior is acceptable, and whether the team can debug both languages. Treat scripts as executable code, not harmless user configuration.

When Should You Choose Groovy?

Choose Groovy when it earns its place: clearer Spock tests, a useful JVM script, an existing Groovy DSL, or a Grails application your team can maintain. For a new Java service with no such need, staying with Java is a sound default. Less boilerplate is useful; a second language still needs an owner.

FAQ

What is Groovy used for?

Groovy is used for JVM scripts, compiled applications, Spock tests, Groovy-based Gradle builds, and Grails web applications. It can complement Java without requiring an application-wide rewrite.

How does Groovy differ from Java?

Groovy adds concise collection syntax, closures, and dynamic method resolution, with optional static checking and compilation. Java and Groovy share the JVM, but their source syntax and some runtime semantics differ.

Can Groovy call Java libraries?

Yes. Groovy can use Java classes and libraries when the runtime and dependencies are compatible. This is library interoperability, not a guarantee that every Java source file is valid Groovy.

Is Groovy dynamically typed or statically typed?

Groovy supports dynamic code and optional static type checking. Use @TypeChecked to check annotated code during compilation, or @CompileStatic to add static compilation as well.

Is Groovy still used in 2026?

Yes: concrete current uses include Spock testing, Gradle's Groovy DSL, and Grails web development. Whether you should adopt it depends on those needs and your team's ability to maintain another language, not on a blanket claim about popularity.

Further Reading

Advertisement

Written by Sam Erickson

Pen name of a software engineer with 20+ years in the industry, from Fortune 500 companies to startups. I write every article on StackChief myself. Author of Mastering the Tech Interview. More about me

Advertisement