5 minute read

Similarities comparing to Java

  • runs on JVM (there is no Groovy Virtual Machine)
  • looks like Java (syntax, classes, keywords)
  • Groovy class compiles to the same bytecode as Java class
  • Groovy bytecode is loaded by JVM like Java class
  • can be used in existing Java project: Groovy JAR in the classpath (e.g. Maven / Gradle dependency) is enough
  • Groovy runtime is a single Java archive (JAR) file
  • strongly typed language (same as Java) - type of variable cannot be changed once it has been declared
  • object-oriented
  • Groovy code can use any existing Java library as-is (Java can also call Groovy code)

Differences comparing to Java

  • follows the principle of least surprise
  • in Groovy, every class and method is public by default, fields are private
  • class name does not need to match the name of the source file
  • Groovy has its own compiler: groovyc (reads Groovy source files and compiles to Java bytecode)
  • dynamic language (Java is static)

Dynamic means: a class / an object can change during runtime (it is not happening in Java). For example, it’s possible to add new methods to a Groovy object (that weren’t in its source code), delegate existing methods to other objects, or even create completely new classes during runtime.

Next, we do not have to specify the type of declared / returned variable (possible to use keywords: var, def). The type will be inferred by Groovy runtime.

We can also assign variable of a different type to recently declared variable:

date = new Date()
date = "Just joking!"
println(date)
  • it’s called dynamically typed or optionally typed language - Groovy still supports the Java way of explicit types, and user can choose any of them for a given variable when declaring:
    Date date = new Date()
    date = "Just joking!"
    // throws exception at runtime
    

    In such case, Groovy runtime will detect assignment of an incorrect type.

  • Groovy is object-oriented (same as Java) - but allows scripting (in Java, everything must be put into a class)
  • GDK, not JDK
  • less verbose
  • own libraries (for example, web and object relational frameworks)
  • Groovy closures vs Java lambda expressions
  • Groovy (like Ruby or Python) supports duck typing, when Java has strict inheritance and polimorphism

Duck typing: object type is recognized / determined on the basis on methods implemented by this object or its properties. Java has nominative typing (contrary to duck typing): object type depends on its declaration and inheritance (place it has in objects’ hierarchy).

  • return keyword is optional (lastly evaluated statement is the result implicitly returned from a method)
  • semicolons are optional
  • parenthesis in method call are optional:
    println("This string")
    // or
    println "This string"
    
  • no difference between checked and unchecked exceptions - throws clauses in method signature are ignored by Groovy compiler
  • == works like equals() (both are allowed)
  • to check identity, use is() instead of ==
  • Groovy truth (see below)
  • @Immutable to make an object (GroovyBean) immutable (and thread-safe)
  • safe-dereference operator (?) instead of null-check
    // Java-like
    if (thisObject != null) thisObject.getProperty();
    // Groovy-like
    thisObject?.getProperty
    
  • Elvis operator (?:) instead of ternary
// Java-like
String customerName = customer.getName;
String name = customerName != null ? customerName : "Unknown";

// Groovy-like
// First, it implicitly translates null to false - null check is not needed
name = customerName ? customerName : "Unknown"
// Use Elvis and simplify
name = customerName ?: "Unknown"
  • String written with quotes or double quotes
  • GString class - enhanced String (double quotes only) - these are not Java Strings underneath, not to be used as keys in maps or to compare with equals()
    today = new Date()
    String enhancedString = "This is an example of Groovy enhanced String (GString), generated on ${today}."
    
  • simply clever: first-class (in-built) support for regex, XML, closures

Groovy is close relative of Java

  • Groovy code can create Java classes with the new keyword
  • Groovy code can call Java methods
  • Groovy classes can extend Java classes
  • Groovy classes can implement Java interfaces
  • Groovy code can be called from Java through GroovyShell, GroovyClassLoader, GroovyScriptEngine

Groovy truth

Objects can be evaluated to booleans (like in Python). Groovy treats all objects as true unless:

  • object is an empty string
  • object is a null reference
  • object is the zero number
  • object is an empty collection (map, list, array, and so on)
  • object is the false Boolean (it’s rather obvious)
  • object is a regex matcher that fails

// class is public by default
class GroovyIntro {
    
    /**
     * ### def keyword:
     * - def with variables - type of a variable unknown, will be known later
     * - def with methods - return type of a method unknown
     * */

    // fields are private by default
    int id
    String title // no semicolons

    // method is public by default
    // psvm method similar to Java-style
    static void main(String[] args) {
        GroovyExample groovyExample = new GroovyExample()
        // getters and setters available automatically
        groovyExample.setContent("testContent")
        // even simplier direct access
        groovyExample.content = "anotherTestContent"
        // directly or by getter
        println(groovyExample.content)
        // println is groovy helper shortcut but we can use dollar
        println("Content of the file is $groovyExample.content")
        println(groovyExample.transform())

        // so-called map-based constructors (instead of setters or parametrized constructors)
        def anotherGroovyExample = new GroovyExample(content: "test content")

        // map
        // it's LinkedHashMap by default
        Map<String, Integer> map = ["input1":1, "input2":2]

        // list
        List<String> list = ["A"]
        // add
        list << "B" << "C"
        print(list)
        // replace
        list[0] = "X"
        print(list)

        // input reading
        // String testInput = new File ( "src/test/resources/quotes.txt").text
        // line by line
        // File("src/test/resources/quotes.txt").readLines()
        // to read xml or json, use Slurper (deprecated)

        /**
         * Closures
         * */

        // full notation
        Closure simple = { int x -> return x * 2}
        // if not fails, shows nothing
        assert simple(3) == 6
        // simple notation, return is optional
        def simpler = { x -> x * 2}
        assert simpler(3) == 6
        // bi-function
        def twoArguments = { x,y -> x + y}
        assert twoArguments(3,5) ==8

        /**
         * In Groovy, the == operator isn’t testing identity like Java.
         * It calls the equals() method of the object.
         * Object identity in Groovy is compared by the is() method.
         * Thus object1.is(object2) is the Groovy way of testing identity.
         * */

        /**
         * Methods using closures, eg. on collections, like list.every(elem ->  elem.endsWith()):
         * every(closure)
         * any (closure)
         * find(closure)
         * findAll(closure)
         * */

        /**
         * ### return keyword:
         * - return keyword is also optional
         * - the last evaluated statement in a method is the result
         of the method in that case.
         * */
    }
    
}