Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
A Tour of Groovy Chris Wong [email protected] 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[b] a << b switch (a) { case b: ... } a == b a<b a.plus(b) a.getAt(b) a.leftShift(b) b.isCase(a) a.equals(b) a.compareTo(b) < 0 Groovy convenience operators ?: elvis Java: Groovy: name = name != null ? name : "default" 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() GroovyBeans and JavaBeans // Groovy class MyBean { String item } // Java class MyBean { private String item; public String getItem() {…} public void setItem(…) {…} } MyBean b = new MyBean(item:‘foo’) MyBean b = new MyBean(); b.setItem(“foo”); String val = b.item String val = b.getItem(); b.item = ‘bar’ b[‘item’] = ‘bar’ b.setItem(“bar”) 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 // save object } } use (PersistenceCategory) // all objects now have new MyBean().save() } { o) { { save() method 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 Poor IDE support Write critical areas in Java Groovy performance rapidly improving IntelliJ IDEA's JetGroovy coming along nicely Stack dumps are a pain Questions/discussion Thanks for listening! [email protected]