I saw Ken Kousen deliver his intro to Groovy talk today at the NY Java SIG. While I’ve done some small things with Groovy, I’ve forgotten a lot of what I once knew. Some of it, i remembered/used but am including here so this isn’t random facts but a summary of what was presented. Blogging about it this time in hopes I can retain more.
First of all, Ken is a great speaker. If you have the chance to see him in person, go. He:
- is entertaining – programmer humor
- presents info clearly
- has well thought out examples
- switches well between the groovy console, command line, browser and slides. While there were frequent switches, it was easy to follow
- live examples. Surprises and mistakes and all Icndb.com for humor in json examples provided energy towards the end
Useful links
- Groovy.codehaus.org – which has Groovy APIs, Groovy extensions to JDK APIs and the developer guide.
- Code examples from Making Java Groovy book
- Groovy console online (not talked about today, but I like it)
Now on to Groovy
What is groovy
- Groovy is like Java 3. Other jvm languages are simulating other languages like jythong or special purpose like functional languages. Groovy is a general purpose like a next generation OO language. Plus you can fall back to Java and make it “groovier” later [which is great for learning]
- Compiles to bytecode. Also a C compiler is available.
- If the name of your groovy file matches the name of the class, you can only have a class in the file. Otherwise you can put multiple classes or even just scripts in the file. Ken’s convention is to use underscores in filenames for scripts to identify them.
- Hello world is println “hi” [yes, that’s it]
- Parens are optional “until they are not”. They have a low precedence. Can leave out if obvious where they go
- Semicolons are always optional
- Perls goal is to write the shortest code possible. Groovy’s goal is to write the simplest code possible.
- Testing and build are the place to start with groovy when introducing into a reluctant organization
Options to run
- groovy foo.groovvy – don’t have to compile first. Should compile first when use it for real though. If want to integrate with java, must run groovyc to compile since java requires class files.
- The class files require groovy in the claspath to run with “java” rather than “groovy”. In groovy home, embedable directory contains groovy-all and groovy-allindy. The later is for invoke dynamic in Java
Tools
- Groovy Grails Tool Suite – for Eclipse
- Groovy menu has convert file extensions to groovy where right click java class. This lets you refactor slowly. [Or if create java class by accident like often do]
Operator overloading
- Every operator corresponds to a method. This means if your class implements that method, you can use that operator. This lets you write new Date() + 7 to get a date a week in the future.
- ** is power operator
- [] goes with getAt or putAt methods. This is what lets you say s[-1] or s[0..2] instead of pure array indexes. The getAt/putAt methods understand how to navigate. The methods also know to call next for 0..2 and prev for -3..-1. I also learned you can specify multiple ranges such as as s[0..2,4..5]
- In groovy == calls the equals method. Which means just converting a java class can result in an infinite recursion. Run your tests when refactoring
- To append: list << value
Groovy Types
- 123.getClass().getName() is an Integer. If you make it bigger becomes long or BigInteger dynamically.
- 2 – 1.1 uses BigDecimal so accurate unlike 2d – 1.1d which has Java roundoff error from using doubles.
- GString “test ${name}” uses interpolation to substitute the variable name. You don’t need braces if just one variable
- Single quotes are Java strings
- Double quotes are groovy strings
- Triple quotes are for multi line strings. Useful for SQL.
- Def means don’t know or care about type
- Duck typing. Can call any methods on def oject. If method exists at runtime ,call it. Else throw MissingMethodException at runtime.
- Map keys assumed to be Strings
Groovy translation
- S.class.name works. When it looks like you are referencing a private field, groovy adds get or set to call appropriate methods. The runtime environment provides getter and setter methods so you don’t need to write them
- Don’t need to type return belcause last expression is automatically returned
Plain Old Groovy Object (POGO)
Generates at runtime:
- getter/setter – If don’t want setter, add final to instance variable. If don’t want getter or setter on instance variable, type private.
- map based constructor
- class and methods public by default
- instance variables private by default
All you have to write is a class and the types. If you implement a method, Groovy will use yours and not generate it. If using the map based constructor, Groovy calls the default constructor and any appropriate setters. This means you don’t need overloaded constructors.
1 2 3 4 5 6 7 8 9 10 | class Person{ String first String last } Person p = new Person() p.setFirst( "f" ) println "$p.first" new Person(first: 'a' , last: 'b' ) |
Walkthru of converting a POJO to a POGO
- Remove getters and setters
- Remove private from instance variables
- Remove semicolons
- Remove constructor – need to use map constructor – affects callers [not backward compatible to simplify all the way]
- Remove public on class
- Remove import for java.util.Date
- Add @Canonical which includes @ToString, @TupleConstructor and @EqualsAndHashCode. All are AST transformations
- [1,2] creates list
- LinkedList a = [1] makes the desired type
- [1] as Set also creates the desired type
Closure
1 2 3 4 5 | listOfStrings. each { /* code using it as default loop variable */ } map. each { k,v -> /* code */ } list. collect { /* transform to new list where results make up the new list */ }. join ( ',' ) // map reduce |
Closure coercion can be used for an anonymouse inner class
{ /* code */} as FilenameFilter
Useful when an interface has only one method because uses implemetation for all methods in interfaces. Could pass a map of closures but might as well implement interface then.
Helpful classes/methods
- Groovy adds toURL to String class and getText to Url class masking query.toUrl().text a one liner
- XMLSlurper lets you get a dom tree from a URL which you can then navigate as tree.root.result[o].geometry.
location.lat - db.rows(“selet * from table”)
- db.eachrow(” query “){ /*code */}
- groovy.json.JsonSlurper().
parseText(json) - groovy.xml.MarkupBuilder to create. Similarly for xml, json and ant
- Must test code since constraints we are used to are gone
- Spock over GroovyTestCase – very nice framework. See example in github/book
Random interesting tips
- Can use map based constructor on a pojo too because groovy will call default constructor and set methods
- foo.with{} calls foo.xxx for any methods not found in scope
- Meta programming: add methods to class that need. Even to a java class. Complex.metaClass.plus= {}. Every class has a metaclass.
You forgot to mentioned that Ken is a Boston Red Sox fan
That’s right. And being a Red Sox fan is something to promptly bring up when bonding with a NY audience!