An independent editorial resource for Java practitioners.

Browse the discussion resource

Java Chronicles

Language notes · Groovy series

Introduction to Groovy Part II

A practical tour of Groovy’s truth rules, regular-expression syntax, operator methods, and the property conventions that turn ordinary Java-style objects into POGOs.

Laptop displaying code during a programming session

In the first part of the series, we covered the first steps in writing Groovy scripts, including closures, concise syntax, and the language’s basic data types. This second instalment looks at features that make Groovy especially approachable for Java developers: flexible conditional evaluation, native regular expressions, operator methods, and simple property declarations.

The Groovy Truth

Java requires a condition to resolve to a boolean value. Groovy broadens that model with a set of runtime rules often called Groovy Truth. Rather than requiring an explicit comparison in every case, common values can be evaluated directly in a condition.

TypeEvaluates as true when
BooleanThe value is true.
MatcherAt least one match is present.
CollectionThe collection is not empty.
MapThe map is not empty.
String or GStringThe string contains characters.
Number or characterThe value is not zero.
Other objectsThe reference is not null.

The relevant type is determined at runtime. That small shift makes conditional code more compact while preserving the intent of a test.

Regular expressions

Groovy gives regular expressions direct language support. A slash-delimited expression can be used without the escaping ceremony often needed when a pattern is written as a Java string. The language also provides operators for searching, checking a complete match, and creating a compiled pattern.

  • =~ searches for a match and returns a matcher.
  • ==~ checks whether an entire value matches and returns a boolean.
  • ~ produces a compiled pattern.

Listing 3.1 · Matching text

def text = "Groovy is a dynamic language"
assert text =~ /ua/

matcher = text =~ /ua/
assert matcher instanceof java.util.regex.Matcher

def match = text ==~ /.*ua.*/
assert match instanceof java.lang.Boolean
assert match

def pattern = ~/oovy/
def result = pattern.matcher(text)
assert result instanceof java.util.regex.Matcher

The first two forms search within the supplied text or check the whole text, while the final form compiles the expression for reuse. A compiled pattern can be the clearer choice when the same expression is applied repeatedly.

Operator overloading

Groovy maps many operators to methods with conventional names. Classes that provide those methods can participate in ordinary-looking expressions, keeping domain code readable without requiring special syntax at every call site.

OperationMethod name
a + ba.plus(b)
a - ba.minus(b)
a * ba.multiply(b)
a / ba.div(b)

Listing 4.1 · Operators in familiar form

text = "Programing" - "ing" + "er"
assert "Programer" == text

list = [1, 2, 3]
list += [4, 5, 6]
assert [1, 2, 3, 4, 5, 6] == list

list << 7
assert [1, 2, 3, 4, 5, 6, 7] == list

s = "A" * 5
assert s == "AAAAA"

These conventions also make it possible to shape small domain-specific languages. The useful question is not whether every operator can be overloaded, but whether an expression remains obvious to the next reader.

From POJOs to POGOs

Java developers are familiar with POJOs: small objects that keep application state and behaviour straightforward. Groovy offers a related convention commonly called a POGO, or Plain Old Groovy Object. A property declared without an access modifier receives accessor behaviour automatically, so repetitive getters and setters do not need to be written by hand.

Listing 5.1 · A simple POGO

class Person {
  String name
  String lastname
  private int id

  String toString() { "${name} ${lastname}" }
}

Person person = new Person(name: 'Andres', lastname: 'Almiray')
assert "Andres Almiray" == person.toString()
person.lastname = "Jaramillo"
assert "Andres Jaramillo" == person.toString()
person['lastname'] = "Almiray"
assert "Andres Almiray" == person.toString()

Named-style construction is available for the declared properties. Property access through dot notation is resolved through Groovy’s object model, and bracket notation may be used where it helps make dynamic access explicit. Direct field access is available with .@ when that distinction is genuinely required.

Listing 5.2 · Properties and fields

class Person {
  String name
  String lastname
  private int id

  String toString() { "${name} ${lastname}" }
  def getFullName() { "${name} ${lastname}" }
}

Person person = new Person(name: 'Andres', lastname: 'Almiray')
assert person.name == "Andres"
assert person.@name == "Andres"
assert person.fullName == "Andres Almiray"

Conclusion

Groovy’s conditional rules, regular-expression support, operator conventions, and properties all aim at reducing incidental ceremony around ordinary programming tasks. For Java developers, the value is often in recognising where the language can make a small piece of code more direct while keeping its purpose clear.

Related reading

More notes for JVM developers.