290 likes | 423 Views
A Tour of Groovy. Chris Wong cwong@makanasolutions.com. Your code in Java …. enum PeriodType { WEEKLY, MONTHLY, QUARTERLY, ANNUALLY } @Entity class Invoice { @Id int id; @OneToMany List<Item> items; PeriodType periodType; public List<Item> getFunnyItems() {
E N D
A Tour of Groovy Chris Wong cwong@makanasolutions.com
Your code in Java … enum PeriodType { WEEKLY, MONTHLY, QUARTERLY, ANNUALLY } @Entity class Invoice { @Id int id; @OneToMany List<Item> items; PeriodType periodType; public List<Item> getFunnyItems() { List<Item> funnyItems = new ArrayList<Item>(); for (Iterator<Item> i = items.iterator(); i.hasNext(); ) { Item item = i.next(); if (item.isFunny()) funnyItems.add(item); } return items; } }
Your code in Groovy! enum PeriodType { WEEKLY, MONTHLY, QUARTERLY, ANNUALLY } @Entity class Invoice { @Id int id; @OneToMany List<Item> items; PeriodType periodType; public List<Item> getFunnyItems() { List<Item> funnyItems = new ArrayList<Item>(); for (Iterator<Item> i = items.iterator(); i.hasNext(); ) { Item item = i.next(); if (item.isFunny()) funnyItems.add(item); } return items; } }
Hello, world Legal code, but can omit plumbing class Foo { public static void main(String[] args) { System.out.println("Hello, world"); } }
Hello, world Groovy also provides some shortcuts … System.out.println("Hello, world");
Hello, world Unnecessary punctuation just adds clutter … System.out.println("Hello, world");
Hello, world System.out.println('Hello, world');
Why Groovy? The power of a dynamic language plus … • JSR 241: Java standard • Two-way contract: • a Groovy class is a Java class: it’s all bytecodes. Groovy and Java can extend each other’s classes. • Seamless integration with Java: annotations, generics, enums, familiar syntax. • The Groovy platform is the Java platform: • the J2SE library, debugging, profiling etc. • Spring, Hibernate, web services, TestNG
Some Groovy language features • Dynamically typed • Closures • Everything is an object. No primitives. • == means equals. Really. • Native syntax for lists, maps, regex • Operator overriding • Compact, expressive, readable
Strings greeting = 'Hello' println "$greeting, world" println """ Today's date is ${new Date().toGMTString()} Nice day, isn't it? """ greeting = "Hello, world" greeting[7] == 'w' greeting[2..4] == 'llo'
Closures • Behavior as objects • Default argument is “it”, optional. def squareIt = { return it * it } assert squareIt(5) == 25 10.times { println “I will not talk in class” } • Captures variables in the lexical scope int x = 10 Closure addToX = { addThis -> x += addThis } addToX(2) assert x == 12
Lists and maps mylist = [1, 2, 3, 4, 5] // an ArrayList assert mylist[0] == 1 mylist[2..3] = [] // deleted 3, 4 [2,3,4].collect { it * 2 } == [4, 6, 8] [1,2,3].find { it > 1 } == 2 [1,2,3,[1,[2,3]]].flatten().unique() == [1, 2, 3] mylist.each { doSomethingWith(it) } mymap = [a:1, b:2, c:3] // a HashMap mymap['a'] == mymap.a // == mymap.get("a") mymap['c'] = 5 // mymap.put("c", 5)
Ranges and regex • Ranges • (1..10).each { it -> println it } • switch (age) { case 15..30: … } • for (i in 1..10) { … } • 'Hello, world'[2..4] == 'llo' • Regex if ('rain' =~ /\b\w*ain\b/) println '"rain" does rhyme with "Spain"!'
Operator overriding Override operators by overriding methods: • a + b a.plus(b) • a[b] a.getAt(b) • a << b a.leftShift(b) • switch (a) { case b: ... } b.isCase(a) • a == b a.equals(b) • a < b a.compareTo(b) < 0
Groovy convenience operators • ?: elvis Java: name = name != null ? name : "default" Groovy: name = name ?: "default" • ?. safe dereference. No worry about nulls. street = user?.address?.street • *. spread dot. Invoke on all items, return list. List result = invoice.lineItems*.total()
// Groovy class MyBean { String item } MyBean b = new MyBean(item:‘foo’) String val = b.item b.item = ‘bar’ b[‘item’] = ‘bar’ // Java class MyBean { private String item; public String getItem() {…} public void setItem(…) {…} } MyBean b = new MyBean(); b.setItem(“foo”); String val = b.getItem(); b.setItem(“bar”) GroovyBeans and JavaBeans
Why brevity matters: Quicksort function sort(array) // pseudocode from Wikipedia var list less, greater if length(array) ≤ 1 return array select a pivot value pivot from array for each x in array if x < pivot then append x to less if x > pivot then append x to greater return concatenate(sort(less), pivot, sort(greater)) -------------------------------------------------------- def sort(list) { // Groovy implementation if (list.size() <= 1) return list def pivot = list[0] def less = list.findAll {it < pivot} def same = list.findAll {it == pivot} def greater = list.findAll {it > pivot} sort(less) + same + sort(greater) }
Quicksort in Java public static void qsort(Comparable[] c,int start,int end){ if(end <= start) return; Comparable comp = c[start]; int i = start,j = end + 1; for(;;){ do i++; while(i<end && c[i].compareTo(comp)<0); do j--; while(j>start && c[j].compareTo(comp)>0); if(j <= i) break; Comparable tmp = c[i]; c[i] = c[j]; c[j] = tmp; } c[start] = c[j]; c[j] = comp; qsort(c,start,j-1); qsort(c,j+1,end); } public static void qsort(Comparable[] c){ qsort(c,0,c.length-1); }
Object graph navigation: GPaths class Invoice { List items; … } class Item { Product product; int total() {…} … } class Product { String name; … } List<Invoice> invoices = …; // get all product names where item total > 7000 List result = invoices.items.grep{it.total() > 7000}.product.name // Java version: List result = new ArrayList(); for (Iterator<Invoice> i = invoices.iterator(); i.hasNext(); ) { List items = i.next().getItems(); for (Iterator j = items.iterator(); j.hasNext(); ) { Item item = (Item) j.next(); if (item.total() > 7000) result.add(item.getProduct().getName()); } }
Dynamic Groovy: multimethods class Equalizer { boolean equals(Equalizer e) {...} boolean equals(Object o) {...} } Object obj = new Equalizer() obj.equals(new Equalizer())
Dynamic Groovy: categories // Dynamically add methods to any class class PersistenceCategory { static void save(Object o) { // save object } } use (PersistenceCategory) { // all objects now have save() method new MyBean().save() }
Dynamic Groovy: meta programming • Change class/object behavior at runtime • Meta-Object Protocol (MOP) • You can intercept method calls and property accesses • invokeMethod(...) • getProperty(...) • setProperty(...) • etc
MarkupBuilder builder = new groovy.xml.MarkupBuilder() builder.numbersAndSquares { description 'Numbers and squares' (3..6).each { number (value: it, square: it*it) } } <numbersAndSquares> <description>Numbers and squares</description> <number value='3' square='9' /> <number value='4' square='16' /> <number value='5' square='25' /> <number value='6' square='36' /> </numbersAndSquares>
SwingBuilder swing = new SwingBuilder() frame = swing.frame(title: 'Hello, world') { panel(layout: new BorderLayout()) { label(text: 'Hello, world', constraints: BorderLayout.CENTER) button(text: 'Exit', constraints: BorderLayout.SOUTH, actionPerformed: { System.exit(0) }) } } frame.pack() frame.show()
Domain-specific languages (DSL) • A DSL “is a mini-language aiming at representing constructs for a given domain” • Groovy features for DSLs: add new methods/properties to classes, override operators. • E.g. unit manipulation: • println 30.km/h + 2.m/s * 2 • println 3 * 3.mg/L • println 1/2.s - 2.Hz
Grails ORM (GORM) class Book { String title String author Date releaseDate } book = Book.get(id) // let's change the title book.title = 'War and Peace' book.save() Book.listOrderByTitle() Book.findByReleaseDateBetween(startDate, endDate)
Groovy warts • SLOW • Write critical areas in Java • Groovy performance rapidly improving • Poor IDE support • IntelliJ IDEA's JetGroovy coming along nicely • Stack dumps are a pain
Questions/discussion Thanks for listening! cwong@makanasolutions.com