Java without Java - Groovy

Content:

  1. Introduction
  2. Declarations
  3. null handling
  4. Built in types
  5. Operations
  6. Control structures
  7. Object Oriented Programming
  8. Generic Programming
  9. Functional Programming
  10. Groovy and Java
  11. Runtime
  12. Scripting
  13. DSL features
    1. General
    2. Builders
  14. Why switch to Groovy
  15. Versions

Introduction:

Groovy is Java like languages with support for both dynamic and static typing.

Groovy is a language with a turbulent history.

The short version is:

Year Event
2003 Development of Groovy starts
2004 JSR 241 initiated
2005 Development of Grails start
2007 Groovy version 1.0 released
2008 Grails version 1.0 released
2012 JSR 241 dormant
Groovy 2.0 released
2015 Groovy moves from Codehaus to Apache

Groovy is used for many different purposes:

Note: even though Grails is a huge part of Groovy usage then this article will not cover any Grails usage.

Because Groovy is so Java like then it is relative easy for Java develoeprs to start with, but it can also be a bit deceiving because the nature of the language is very different.

The entire article assumes that the reader is proficient in the Java language and everything is explained by comparing it to Java.

Besides Java syntax then some C# and Python syntax will also be shown when it helps understand Groovy.

This is not a complete reference to Groovy. This only covers some of the more important features. For more details see the Groovy Documentation or get a Groovy book.

Declarations:

Variable declarations are different in Groovy:

Groovy Java equivalent Java 10+ equivalent C# equivalent Python equivalent
v = 123 N/A var v = 123; var v = 123; N/A
int v = 123 int v = 123; int v = 123; int v = 123; N/A
final int v = 123 final int v = 123 final int v = 123 N/A N/A
def v = 123 N/A N/A dynamic v = 123 v = 123

Example:

package jwj

final iv1 = 123
//iv1 = 456
iv2 = 456
println("$iv1 $iv2")
iv2 = 789
println("$iv1 $iv2")
final int iv3 = 123
//iv3 = 456
int iv4 = 456
println("$iv3 $iv4")
iv4 = 789
println("$iv3 $iv4")
//iv4 = "ABC" // Note: runtime error not compile time error
def iv5 = 123
println("$iv5")
iv5 = 456
println("$iv5")
//c = iv5.charAt(0)
iv5 = "ABC"
println("$iv5")
c = iv5.charAt(0)
println("$iv5")

It should be obvious by now that Groovy is different from Java.

null handling:

Groovy basically use Java type system and the way it handles null. It just have a ?. operator to handle null references.

Groovy Java equivalent C# equivalent
int v int v; int v;
Integer v Integer v; int? v;
MyClass o MyClass o; MyClass o;
res = o.m() res = o.m(); res = o.m();
res = o?.m() if(o != null) res = o.m(); else res = null;
or:
res = (o != null) ? o.m() : null;
res = o?.m()
res = a ?: b if(a != null) res = a; else res = b; res = a ?? b;

Example:

package jwj

//int iv1 = null // Note: runtime error not compile time error
Integer iv2 = null
println("${iv2 == null}")
String sv = null
println("${sv == null}")
sv2 = sv?.substring(0, 1)
println("${sv2 == null}")

Built in types:

Groovy has the same basic types as Java.

Groovy Java equivalent C# equivalent
byte byte sbyte
Byte java.lang.Byte sbyte?
short short short
Short java.lang.Short short?
int int int
Integer java.lang.Integer int?
long long long
Long java.lang.Long long?
float float float
Float java.lang.Float float?
double double double
Double java.lang.Double double?
char char char
Char java.lang.Character char?
boolean boolean bool
Boolean java.lang.Boolean bool?
String java.lang.String string
void void or Void void

Groovy are different regarding literals.

Decimal number literals:

literal type
123.456f float
123.456d double
123.456 BigDecimal

String literals:

literal type
"ABC" variable substitution, single line
"""ABC""" variable substitution, multi line
'ABC' no variable substitution, single line
'''ABC''' no variable substitution, multi line

Arrays are also like in Java.

Example:

package jwj

byte vb = 123
println("$vb")
short vs = 123
println("$vs")
int vi = 123
println("$vi")
long vl = 123
println("$vl")
float vf = 123.456f
println("$vf")
double vd = 123.456d
println("$vd")
char vc = 'A'
println("$vc")
boolean v = true
println("$v")
String vs1 = "ABC"
println("$vs1")
String vs2 = """ABC"""
println("$vs2")
String vs3 = 'ABC'
println("$vs3")
String vs4 = '''ABC'''
println("$vs4")
BigInteger vbi = 123g
println("$vbi")
BigDecimal vbd = 123.456
println("$vbd")

Groovy has a compact way to specify list and map values.

Lists can be specified as [ value_1, ..., value_n ].

Maps can be specified as [ key_1: value_1, ..., key_n: value_n ].

Example:

package jwj

lst1 = [1, 2, 3]
println("$lst1")
println(lst1.getClass().getName())
lst2 = ["A", "BB", "CCC"]
println("$lst2")
println(lst2.getClass().getName())
mp1 = [1: "A", 2: "BB", 3: "CCC"]
println("$mp1")
println(mp1.getClass().getName())
mp2 = ["A": 1, "BB": 2, "CCC": 3]
println("$mp2")
println(mp2.getClass().getName())

Operations:

Groovy has the normal arithmetic operators: +, -, *, / and %.

Note that Groovy int / produces a decimal result - to get an int result use intdiv method.

Groovy Java equivalent C# equivalent Python 2.x equivalent Python 3.x equivalent Pascal equivalent
a / b a * 1.0 / b a * 1.0 / b a * 1.0 / b a / b a / b
a.intdiv(b) a / b a / b a / b a // b a div b

Groovy has the normal comparison operators: ==, !=, <, <=, > and >=.

Note that == is same value and Groovy has a separat method is for same identity.

Groovy Java equivalent C# equivalent
a == b a.equals(b) a.Equals(b)
or:
a == b
a.is(b) a == b Object.ReferenceEquals(a, b)
a <=> b a.compareTo(b) a.CompareTo(b)

Groovy has the normal boolean operators: &&, || and !.

Groovy has the same type conversions as Java.

Groovy has the same bitwise operators as Java.

Groovy has builtin regex support.

Groovy Java equivalent C# equivalent
p = ~/xxxxx/ Pattern p = Pattern.compile("xxxxx"); Regex p = new Regex("xxxxx");
m = s =~ /xxxxx/ Pattern p = Pattern.compile("xxxxx");
Matcher m = p.matcher(s);
Regex p = new Regex("xxxxx");
MatchCollection m = p.matches(s);
s ==~ /xxxxx/ Pattern.matches("xxxxx", s) Regex.IsMatch(s, "xxxxx")

Groovy has a spread operator that can expand the elements of a list.

Groovy Java equivalent Java 8+ equivalent
lsta = [1, 2, 3]
lstb = [*lsta, 4]
List<Integer> lsta = Arrays.asList(1, 2, 3);
List<Integer> lstb = new ArrayList<Integer>(lsta);
lstb.add(4);
List<Integer> lsta = Arrays.asList(1, 2, 3);
List<Integer> lstb = new ArrayList<Integer>(lsta);
lstb.add(4);
lst = [1, 2, 3]
m(*a)
List<Integer> lst = Arrays.asList(1, 2, 3);
m(lst.get(0), lst.get(1), lst.get(2));
List<Integer> lst = Arrays.asList(1, 2, 3);
m(lst.get(0), lst.get(1), lst.get(2));
lstx = [new X(v: 1), new X(v: 2), new X(v: 3)]
lstv = lstx*.v
List<X> lstx = Arrays.asList(new X(1), new X(2), new X(3));
List<Integer> lstv = new ArrayList<Integer>();
for(X o : lstx) lstv.add(o.getV());
List<X> lstx = Arrays.asList(new X(1), new X(2), new X(3));
List<Integer> lstv = lstx.stream().map(o -> o.getV()).collect(Collectors.toList());

Example:

package jwj

class SomeData {
    int v;
    String toString() {
        return "C($v)"
    }   
}

void f(int a, int b, int c) {
    println("$a $b $c") 
}

v1 = 123
v2 = ((4 * v1 + 5).intdiv(6) - 7) % 8
println("$v2") 
byte bv = 123
int iv = 123
bv = iv
iv = bv
b1 = 0x0000001
b2 = b1 << 31
b3 = b1 ^ b2
b4 = ~b3
println("$b4")
iv1 = 123
iv2 = 123
println("${iv1 == iv2}")
println("${iv1.equals(iv2)}")
println("${iv1.is(iv2)}")
println("${iv1.compareTo(iv2)}")
println("${iv1 <=> iv2}")
a = 'A'
b = 'B'
c = 'C'
sv1 = "$a$b$c"
sv2 = "$a$b$c"
println("${sv1 == sv2}")
println("${sv1.equals(sv2)}")
println("${sv1.is(sv2)}")
println("${sv1.compareTo(sv2)}")
println("${sv1 <=> sv2}")
// pattern, find and match operators
def p = ~/\d+/
println(p.matcher("123").find())
println(p.matcher("ABC").find())
def m = "123 456 789" =~ /\d+/
while(m.find()) println(m.group(0))
println("123" ==~ /\d+/)
println("ABC" ==~ /\d+/)
// spread operator
lst = [new SomeData(v: 123), new SomeData(v: 456), new SomeData(v: 789)]
println(lst)
lst2 = lst*.v
println(lst2)
f(*lst2)
lst3 = [*lst2, 0]
println(lst3)

Groovy supports additional string operators on both String and StringBuffer (mutable String) for making String manipulation code simpler.

Groovy Java equivalent
s = "..."
...
ss = s[ix]
String s = "...";
...
String ss = s.substring(ix, ix + 1);
s = "..."
...
ss = s[ix1..ix2]
String s = "...";
...
String ss = s.substring(ix1, ix2 + 1);
sb = new StringBuilder
...
ss = sb[ix1..ix2]
StringBuilder sb = new StringBuilder();
...
String ss = sb.substring(ix1, ix2 + 1);
sb = new StringBuilder
...
sb[ix1..ix2] = "..."
StringBuilder sb = new StringBuilder();
...
sb.replace(ix1, ix2 + 1, "...");
sb = new StringBuilder
...
sb << s1 << s2 << s3
StringBuilder sb = new StringBuilder();
...
sb.append(s1).append(s2).append(s3)

Example:

package jwj

def dump(o) {
    println("${o} (${o.class.name})")
}

s = "ABCD"
dump(s)
c = s[1] // a string "B" not a char 'B'
dump(c)
ss = s[1..2] // a string "BC"
dump(ss)

sb = new StringBuffer()
sb << "X" << s << "X" // "XABCDX"
dump(sb)
sb[3..3] = "X" // changes 'C' to 'X'
dump(sb)
sbs = sb[2..4] // a string "BXD"
dump(sbs)

Control structures:

Groovy has basically the same control structures as Java. Most noticeable difference is that do while loop is missing.

Groovy Java equivalent
if(a) {
    foo()
} else {
    bar()
}
if(a) {
    foo();
} else {
    bar();
}
res = a ? b : c
res = a ? b : c;
switch(x) {
    case 1:
        foo()
        break
    case 2:
        bar()
        break
    default:
        throw new Exception("Ooops")
}
switch(x) {
    case 1:
        foo();
        break;
    case 2:
        bar();
        break;
    default:
        throw new Exception("Ooops");
}
for(i in ia) {
    ...
}
for(int i : ia) {
    ...
}
for(i in 1..10) {
    ...
}
or:
for(int i = 1; i <= 10; i++) {
    ...
}
for(int i = 1; i <= 10; i++) {
    ...
}
while(c) {
    ...
}
while(c) {
    ...
}

Groovy switch is more powerful than traditional Java switch. It accepts many different type of case values. Example:

package jwj

def dump(o) {
    switch (o) {
        case Integer:
            switch (o) {
                case 123:
                    println("123")
                    break;
                case 123..125:
                    println("123..125")
                    break   
                case [126, 127, 128]:
                    println("[126, 127, 128]")
                    break
                case  { o > 1000 }:
                    println("Integer > 1000")
                    break
                default:
                    println("Integer")
                    break
            }
            break
        case String:
            switch(o) {
                case "ABC":
                    println("ABC")
                    break
                case { o.startsWith("B") }:
                    println("startWithB")
                    break
                case ~/^C.*$/:
                    println("Regex match")
                default:
                    println("String")
                    break
            }
            break;
        case List:
            println("List")
            break
        default:
            println("?")
            break
    }
}

dump(123)
dump(124)
dump(127)
dump(456)
dump(10000)
dump("ABC")
dump("BCD")
dump("CDE")
dump("EFG")
dump([1, 2, 3])
dump(new Object())

Groovy has try catch like Java but allow the use of any in catch if not interested in the actual exception. Example:

package jwj

try {
    throw new IOException()
} catch(IOException ex) {
    println("Got it")
}
try {
    throw new IOException()
} catch(Exception ex) {
    println("Got it")
}
try {
    throw new IOException()
} catch(any) {
    println("Got it")
}

Groovy supports both default values for arguments and call by argument name.

Groovy Java equivalent C# equivalent
void m(int v = 123) {
    ...
}
void m() {
    m(0);
}
void m(int v) {
    ...
}
void m(int v = 0)
{
    ...
}
m(v: 1)
N/A
m(v: 1);

Note that Groovy determines choice of overloaded method based on actual type at runtime not declared type like Java.

Example:

package jwj

import groovy.transform.NamedVariant
import groovy.transform.NamedParam


void f(int a = 123, int b = 456) {
    println("$a $b")
}

@NamedVariant
void f2(@NamedParam String a = "ABC", @NamedParam String b = "XYZ") {
    println("$a $b")
}

void m(Object o) {
    println("Object")   
}

void m(String s) {
    println("String")   
}

v = 7
s1 = (v == 0) ? "zero" : "not zero"
println(s1)
a = [1, 2, 3]
for(i in a) {
    println(i)
}
for(i = 0; i < 3; i++) {
    println(a[i])
}
for(i in 1..3) {
    println(i)
}
f(321, 654)
f(321)
f()
f2("CBA", "ZYX")
f2("CBA")
f2()
f2(a: "CBA", b: "ZYX")
f2(a: "CBA")
f2(b: "ZYX")
f2()
m("ABC")
Object o = "ABC"
m(o)

Object Oriented Programming:

OO in Groovy is very similar to OO on Java.

Classes, interfaces, extends, implements, abstract and static are like in Java.

There are two major additions in Groovy compared to Java:

Groovy Java equivalent C# equivalent
class X {
    final int a = 123
    int b
    ...
}
class X {
    private int a = 123;
    public int getA() {
        return a;
    }
    private int b;
    public int getB() {
        return b;
    }
    public void setB(int b) {
        this.b = b;
    }
    ...
}
class X
{
    public int A { get; } = 123
    public int B { get; set; }
    ...
}
abstract class AC {
    ...
    abstract void m()
    ...
}
class CC extends AC {
    ...
    void m() {
        ...
    }
    ...
}
abstract class AC {
    ...
    abstract void m();
    ...
}
class CC extends AC {
    ...
    @Override
    void m() {
        ...
    }
    ...
}
abstract class AC
{
    ...
    abstract void m();
    ...
}
class CC : AC
{
    ...
    override void m()
    {
        ...
    }
    ...
}
interface I {
    ...
    void m()
    ...
}
class C implements I {
    ...
    void m() {
        ...
    }
    ...
}
interface I {
    ...
    void m()
    ...
}
class C implements I {
    ...
    @Override
    void m() {
        ...
    }
    ...
}
interface I
{
    ...
    void m()
    ...
}
class C : I
{
    ...
    void m()
    {
        ...
    }
    ...
}
trait T {
    void m1() = ...
}
abstract class X {
    abstract void m1()
    void m2() {
        ...
    }
}
class Y extends X implements T {
}
N/A (interfaces with default methods in Java 8+ can be misused to achieve the same) N/A

Example:

package jwj

trait Tr {
    void test() {
        println("Test")
    }   
}

abstract class P {
    int iv;
    void dump() {
        println("$iv")
    }
    abstract void test()
}

class C extends P implements Tr
{
    String sv;  
    void dump() {
        super.dump();
        println("$sv")
    }
    static m() {
        println("static m")
    }
}

o = new C(iv: 123, sv: "ABC")
o.dump()
o.test()
o.m()
C.m()

Groovy supports operator overload.

Groovy supports extension methods (but only in use block).

Groovy Java equivalent C# equivalent
class X {
    ...
    X plus(X o) { ... }
    X minus(X o) { ... }
    X times(X o) { ... }
    X div(X o) { ... }
    E getAt(int ix) { ... }
    void putAt(int ix, E o) { ... }
}
N/A
class X
{
    ...
    static X operator+(X a, X b) { ... }
    static X operator-(X a, X b) { ... }
    static X operator*(X a, X b) { ... }
    static X operator/(X a, X b) { ... }
    E this[int] 
    {
        get { return ...; }
        set { ... value ...; }
    }
}
class Extensions {
    static def newmethod(SomeType self, ArgTyp arg)
    {
        // do whatever with self (SomeType) and arg (ArgTyp)
    }
}
N/A
static class Extensions
{
    RetType newmethod(this SomeType me, ArgTyp arg)
    {
        // do whatever with me (SomeType) and arg (ArgTyp)
    }
}

Example:

package jwj

class MyInt {
    int v;
    MyInt plus(MyInt o) {
        return new MyInt(v: v + o.v)
    }
    MyInt minus(MyInt o) {
        return new MyInt(v: v - o.v)
    }
    MyInt multiply(MyInt o) {
        return new MyInt(v: v * o.v)
    }
    MyInt div(MyInt o) {
        return new MyInt(v: v / o.v)
    }
    String toString() {
        return "v=$v"
    }
}

class TenInt {
    int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    int getAt(int ix) {
        return a[ix]
    }   
    int putAt(int ix, int e) {
        a[ix] = e
    }
}

class MyExtension {
    static def plusPowerOf2(Integer self, int n) {
        return self + (1 << n) 
    }
}

i1 = new MyInt(v: 1)
i2 = new MyInt(v: 2)
i3 = new MyInt(v: 3)
i7 = i3 * i2 + i1
println(i7)
ten = new TenInt()
println(ten[7])
ten[7] = 17
println(ten[7])
use(MyExtension) {
    println(1.plusPowerOf2(0))
    println(1.plusPowerOf2(1))
    println(1.plusPowerOf2(2))
    println(1.plusPowerOf2(3))
}

Besides the above extension mechanism Groovy also has a more general expanding meta class mechanism.

Basically methods and properties can be added to any class via its meta class.

Example:

package jwj

Integer.metaClass.plusPowerOf2 = { Integer n -> delegate << n }

println(1.plusPowerOf2(0))
println(1.plusPowerOf2(1))
println(1.plusPowerOf2(2))
println(1.plusPowerOf2(3))

String.metaClass {
    mprint = { Integer n ->  for(i in 1..n) println(delegate) }
    p = "Start"
}

s = "ABC"
s.mprint(3)
println(s.p)
s.p = "Finish"
println(s.p)
s2 = "DEF"
println(s2.p)
println(s.p)

Groovy has a nice annotation for setting up delegations to real implementation class:

package jwj

interface I {
    void m1()
    void m2()
}

class C1 implements I {
    void m1() {
        println("C1.m1")
    }
    void m2() {
        println("C1.m2")
    }
}

class C2 implements I {
    @Delegate
    I real
    void m2() {
        println("Voila")
        real.m2()
    }
}

ox = new C2(real:new C1())
ox.m1()
ox.m2()

Groovy has a nice annotation for providing equals and hashCode methods based on the properties:

package jwj

import groovy.transform.EqualsAndHashCode

class A {
    int iv
    String sv
}

@EqualsAndHashCode
class B {
    int iv
    String sv
}

a1 = new A(iv: 123, sv: "ABC")
a2 = new A(iv: 123, sv: "ABC")
println(a1 == a2)
b1 = new B(iv: 123, sv: "ABC")
b2 = new B(iv: 123, sv: "ABC")
println(b1 == b2)

Generic Programming:

Generic programming in Groovy is similar to generic programming in Java.

Groovy Java equivalent C# equivalent
class C<T> {
    ...
}
class C<T> {
    ...
}
class C<T>
{
    ...
}
class C<T extends MyClass> {
    ...
}
class C<T extends MyClass> {
    ...
}
class C<T> where T : MyClass
{
    ...
}

Example:

package jwj

class G1<T> {
    T o;
}

class GP {
    String toString() {
        return "GP"
    }
}

class GC extends GP {
    String toString() {
        return "GC"
    }
}

class G2<T extends GP> {
    T o;
}

o1int = new G1<Integer>(o: 123)
println(o1int.o)
o1infint = new G1(o: 123)
println(o1infint.o)
o1string = new G1<String>(o: "ABC")
println(o1string.o)
o1infstring = new G1(o: "ABC")
println(o1infstring.o)
//dummy = new G2(o: 123) // Note: runtime error not compile time error
//dummy = new G2(o: "ABC") // Note: runtime error not compile time error
o2p = new G2(o: new GP())
println(o2p.o)
o2c = new G2(o: new GC())
println(o2c.o)

Functional Programming:

Groovy has closures.

Groovy Java equivalent C# equivalent
Closure
@FunctionalInterface
interface SomeInterface {
    ReturnType someMethod(Type1 arg1, Type2 arg);
}
delegate ReturnType name(Type1 arg1, Type2 arg2)
{ Type1 arg1, Type2 arg2 -> ... }
(Type1 arg1, Type2 arg2) -> ...
(Type1 arg1, Type2 arg2) => ...
{ arg1, arg2 -> ... }
(arg1, arg2) -> ...
(arg1, arg2) => ...

Example:

package jwj

eps = 0.0000000001d

double diff(Closure f, double x) {
    return (f(x + eps) - f(x)) / eps
}

double newton_solve(Closure f) {
    x = 1.0
    double xold = 10.0
    while(x/xold < (1 - eps) || x/xold > (1 + eps)) {
        xold = x
        x = x - f(x) / diff(f, x)
    } 
    return x
}

sqrt_func = { double x -> x * x - 2 }
sqrt2 = newton_solve(sqrt_func)
println("$sqrt2 ${sqrt2 * sqrt2}")
curt3 = newton_solve({ double x -> x * x * x - 3 })
println("$curt3 ${curt3 * curt3 * curt3}")
fortg_func = { double x, double a -> x * x * x * x - a }
fort4_func = { double x -> fortg_func(x, 4.0) }
fort4 = newton_solve(fort4_func)
println("$fort4 ${fort4 * fort4 * fort4 * fort4}")

Groovy supports currying and partially applied functions. Closure has curry, rcurry and ncurry methods that return a new Closure with one argument applied.

Closure has a memoize method that direct Groovy to cache the result.

Example:

package jwj

add = { int v1, int v2 -> println("$v1 + $v2 = ${v1 + v2}") }
f1 = add.curry(123)
f1(1)
f1(2)
f1(3)
f2 = add.rcurry(123)
f2(1)
f2(2)
f2(3)
f3 = add.ncurry(0, 123)
f3(1)
f3(2)
f3(3)
f = { int v -> lbl: { println("f($v)"); v > 1 ? v + f(v - 1) : 1 }}
println(f(5))
println(f(10))
f = { int v -> lbl: { println("f($v)"); v > 1 ? v + f(v - 1) : 1 }}.memoize()
println(f(5))
println(f(10))

Groovy and Java:

The basics:

Groovy and Java classes with methods and property accessor/mutator are fully interoperable.

Example:

package jwj;
public class JavaClass {
    private int v;
    public int getV() {
        return v;
    }
    public void setV(int v) {
        this.v = v;
    }
    public void m() {
        System.out.printf("v=%d\n", v);
    }
    public void callback() {
        GroovyClass og = new GroovyClass();
        og.setV(123);
        og.m();
    }
}
package jwj

class GroovyClass {
    int v;
    def m( ) {
        println("v=$v")
    }
}

oj = new JavaClass()
oj.v = 123
oj.m()
oj.callback()

Runtime:

Groovy fundamentally uses the Java runtime, but Groovy has added some extra Groovy specific methods to the classes.

This include collection classes.

Example:

package jwj

lst1 = [1, 2, 3].asImmutable()
println(lst1)
println(lst1.indices.toList())
//lst1.add(4)
//lst1[1] = 0
lst2 = [1, 2, 3]
println(lst2)
println(lst2.indices.toList())
lst2.add(4)
lst2[1] = 0
println(lst2)
println(lst2.indices.toList())
map1 = [ 1: "A", 2: "BB", 3: "CCC" ].asImmutable()
println(map1)
println(map1.keySet())
println(map1.values())
//map1.put(4, "DDDD")
//map1[2] = "X"
map2 = [ 1: "A", 2: "BB", 3: "CCC" ]
println(map2)
println(map2.keySet())
println(map2.values())
map2.put(4, "DDDD")
map2[2] = "X"
println(map2)
println(map2.keySet())
println(map2.values())

Groovy also got a number of methods on collection classes for closure usage:

findAll
list/array to list/array with subset of elements
collect
list/array to list/array with converted elements

And Groovy got a very powerful array/list indexing feature:

[n]
element number n
[n,m]
element number n and m
[n1..n2]
elements numbered n1..n2
[n,n1..n2]
elements numer n and elements numbered n1..n2

Example:

package jwj

lst = [1, 2, 3, 3]
println(lst)
println(lst[1])
println(lst[1,2])
println(lst[1..2])
println(lst[0,2..3])
println(lst[-3])
println(lst[-2..-1])
println(lst.sum())
println(lst.any({ v -> v > 2}))
println(lst.any({ v -> v > 3}))
println(lst.every({ v -> v > 0}))
println(lst.every({ v -> v > 1}))
println(lst.findAll({ v -> v > 1}))
println(lst.join("#"))
lst.each({ println(" $it") })
println(lst.collect({ v -> v + 1}))
println(lst.collect({ v -> "Item: $v"}))

Scripting:

Groovy has builtin script capability very similar to JSR 223.

Example:

package jwj

class SomeClass {
    int v;  
}

def Binding bind = new Binding()
def groovy = new GroovyShell(bind)
def o = new SomeClass(v: 123)
bind.setVariable('o', o)
bind.setVariable('inval', 4)
code = """outval = o.v
println("inside")
o.v = o.v + inval"""
println(code)
groovy.evaluate(code)
def outval = bind.getVariable("outval")
println("$outval $o.v")

DSL features:

General:

Groovy got some features for enabling writing DSL (Domain Specific Language) in Groovy.

The free syntax of Groovy combined with closures enables many natural language syntax features and extending the languages.

Example:

package jwj

class CI {
    def moveto(int n) {
        println("moveto $n")
    }   
}

def move(obj) { [to: { n -> obj.moveto(n) }] }

class CW {
    int a
    String b
}

def with(obj, clo) { obj.with(clo) }

o = new CI()
o.moveto(3)
move o to 3

w = new CW()

w.with {
    a = 123
    b = "abc"
    println("$a $b")
}

with(w) {
    a = 456
    b = "def"
    println("$a $b")
}

Note that Groovy actually comes with with and tap methods so no need to do this. Example:

package jwj

class X {
    int a
    int b
    int c
    int d
    @Override
    def String toString() { "${a} ${b} ${c} ${d}" }
}

o1 = new X()
println("o1 = ${o1}")
o1.with { a = 1; b = 2 }
o1.with { c = 3; d = 4 }
println("o1 = ${o1}")
o2 = new X()
println("o2 = ${o2}")
o2.with { a = 1; b = 2; it }.with { c = 3; d = 4 }
println("o2 = ${o2}")
o3 = new X()
println("o3 = ${o3}")
o3.tap { a = 1; b = 2 }.with { c = 3; d = 4 }
println("o3 = ${o3}")

Builders:

Groovy come with several socalled builders created using Groovy DSL capabilities.

Example building JSON:

package jwj

import groovy.json.*

class IdValJson {
    int id;
    String val  
}

idval = new IdValJson(id: 123, val: "ABC")

def json = new JsonBuilder()
json {
    lbl 'demo'
    data {
        id idval.id
        val idval.val
    }
}
println(json.toString())
println(json.toPrettyString())

Output:

{"lbl":"demo","data":{"id":123,"val":"ABC"}}
{
    "lbl": "demo",
    "data": {
        "id": 123,
        "val": "ABC"
    }
}

Example building XML

package jwj

import groovy.xml.*

class IdValXml {
    int id;
    String val  
}

idvals = [ new IdValXml(id: 1, val: "A"), new IdValXml(id: 2, val: "BB"), new IdValXml(id: 3, val: "CCC") ]

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.all {
    idvals.each { e ->
        one {
            id e.id
            val e.val
        } 
    }
}
println(writer.toString())

Output:

<all>
  <one>
    <id>1</id>
    <val>A</val>
  </one>
  <one>
    <id>2</id>
    <val>BB</val>
  </one>
  <one>
    <id>3</id>
    <val>CCC</val>
  </one>
</all>

For an example building HTML see here.

Example building Swing GUI:

package jwj

import java.awt.*
import javax.swing.*

import groovy.swing.*

class IdValSwing {
    int id;
    String val
}

idvals = [ new IdValSwing(id: 1, val: "A"), new IdValSwing(id: 2, val: "BB"), new IdValSwing(id: 3, val: "CCC") ]

def swing = new SwingBuilder()
swing.edt {
    frame(title: 'Demo', layout : new GridLayout(1, 3), size: [300, 100], show: true) {
        idvals.each { e ->
            button(text:e.id, actionPerformed: { JOptionPane.showMessageDialog(null, e.val) })
        }
    }
}

Why switch to Groovy:

I definitely believe that for some projects it will be beneficial to use Groovy. I am not so sure that many projects in Java today would benefit from using Groovy. To me Groovy is the right JVM language for projects where at least partial dynamic typing is considered beneficial.

Benefits of Groovy (in order of importance):

  1. Save a lot of code for properties
  2. Save a lot of code using rich array/list features and builtin regex support
  3. Java skills are somewhat reusable
  4. More readable code via operator overload
  5. Good support for BigDecimal instead of double

Drawbacks of Groovy (in order of importance):

So if you think Java is good for a task and you are looking for an even better language then Groovy is probably not the rigth choice - look for Kotlin or Scala instead.

But if you think Java is too heavy (too C++ish) for the task and you are looking for something ligther more like Python or VB but you need to utilize existing Java libraries, then Groovy may be perfect for you.

Versions:

Groovy release history:

Version Release date
1.0 January 3rd 2007
1.5 December 7th 2007
1.6 February 18th 2009
1.7 December 22nd 2009
1.8 April 27th 2011
2.0 June 28th 2012
2.1 January 24th 2013
2.2 November 18th 2013
2.3 May 5th 2014
2.4 January 21st 2015
2.5 May 27th 2018
3.0 February 7th 2020
4.0 January 25th 2022

The article above covers Groovy version 2.5. A few selected new features in newer versions are covered below.

Version 3.0:

Standard do while loop:

package jwj

i = 10
do {
    println(i)
    i--
} while(i > 0)

Java style lambdas supplementing traditional Groovy closures:

package jwj

void exec(Closure m, int v) {
    m(v)
}

exec( { v -> println(v) }, 123)
exec( v -> println(v), 123)

Compatible with Java 8 lambdas.

Interface default methods:

package jwj

interface I {
    default void m1() {
        println("m1")
    }
    void m2()
}

class C implements I {
    void m2() {
        println("m2")
    }
}

o = new C()
o.m1()
o.m2()

Compatible with Java 8 interface default methods.

Try with resources:

package jwj

class C implements Closeable {
    public void close() {
        println("close")
    }
}

try(o = new C()) {
    // nothing
}

Compatible with Java 1.7 try with resources.

Identity operators:

package jwj

class C { }

a = new C()
b = new C()
println(a === a)
println(a !== a)
println(a === b)
println(a !== b)

Safe index similar to safe dereference:

package jwj

lsta = [1, 4, 9]
lstb = null
println(lsta[1])
//NPE: println(lstb[1])
println(lsta?[1])
println(lstb?[1])

mapa = ["a": 1, "b": 4, "c": 9]
mapb = null
println(mapa["b"])
//NPE: println(mapb["b"])
println(mapa?["b"])
println(mapb?["b"])

Version 4.0:

Switch expression:

package jwj

enum E { A, B, C }

v = E.B

switch(v) {
    case E.A:
        println("This was A")
        break
    case E.B:
        println("This was B")
        break
    case E.C:
        println("This was C")
        break
}

s = switch(v) {
        case E.A -> "This was A"
        case E.B -> "This was B"
        case E.C -> "This was C"
    }
println(s)

Compaitble with Java 12 switch expression.

Sealed classes with permits:

package jwj

sealed class X permits X1, X2 {
}

class X1 extends X {
}

class X2 extends X {
}

void test(X o) {
    if(o instanceof X1) {
        println("X1")
    } else {
        println("X2")
    }
}

test(new X2())

Compatible with Java 15 sealed classes with permits.

GINQ (incunabting):

package jwj

class X {
    int a
    String b
    String toString() {
        return "(" + a + "," + b + ")"
    }
}

lst = [ new X(a: 1, b: "A"), new X(a: 2, b: "BB"), new X(a: 3, b: "CCC") ]
println(lst)

lst2 = GQ { from elm in lst where elm.a > 1 select elm.b }
println(lst2)

class Y {
    String b
    double c
    String toString() {
        return "(" + b + "," + c + ")"
    }
}

lst3 = [ new Y(b: "A", c: 1.2), new Y(b:"BB", c: 3.4) ] 
println(lst3)

lst4 = GQ { from elm in lst join elm3 in lst3 on elm.b == elm3.b select elm.a, elm3.c }
for(o4 in lst4) println(o4.a + " " + o4.c)

Heavily inspired by .NET LINQ.

Contracts (incubating):

package jwj

import groovy.contracts.*

@Invariant({ a >= 0 && b >= 0 })
class X {
    int a
    int b
    @Requires({ a >= 1 && b >= 1 })
    @Ensures({ a >= 2 && b >= 2 })
    def inc() {
        a++
        b++
    }
    String toString() {
        return "(" + a + "," + b + ")"
    }
}

o = new X(a:1, b:1)
println(o)
o.inc()
println(o)

Article history:

Version Date Description
1.0 March 6th 2020 Initial version
1.1 March 4th 2022 Add version history
1.2 November 17th 2022 Add list/map values example and expanding meta class example

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj