Download - Groovy unleashed
Welcome To… Groovy!
– The Catalyst Language for Programmers
Presentation By-Isuru Samaraweera
Agenda
• Introduction to Groovy• Key Features• Closures• Operator Overloading• Array Slicing and looping
• Collections
• Dynamic Methods/Mixins and Properties• Regular Expressions• File IO• Database Operations
What is Groovy?• Java-like scripting language for the JVM• Dynamic Language• Inspired by Ruby,Python,SmallTalk and Perl • Open Source language
– Apache2.0 license– [email protected] – [email protected]
• Seamless integration with Java – Follow the mantra…Java is Groovy,Groovy is Java
• Web Application Development– Groovelets,GSP,Grapplet
• Sole alternative dynamic language for the JVM fully supporting frameworks like Spring, Hibernate– Grails– Coding by Convention
• Mobile Application Support • Official web site http://www.groovy-lang.org/
Installation and Configuration
• Prerequisites– JDK1.4 or higher installed and system path should point to %JAVA_HOME%/bin
• Download Groovy distribution from http://www.groovy-lang.org/download.html • Unzip the groovy archive
– Set the GROOVY_HOME environment variables.– Add %GROOVY_HOME%\bin to your system path – Try opening groovyConsole.bat
• Eclipse Plug-in– https://github.com/groovy/groovy-eclipse/wiki
• IntelliJ Idea Plug-in-Community edition– http://www.jetbrains.net
Key Language Features
• Pure Object Oriented 3.times { println "hello" } • Dynamic Typing/Duck typing• Closures• Currying• Operator Overloading• Array Slicing• Dynamic Methods• Expandos• Static imports• Annotations• Covariant return types• POGO support• Mixins
Java Vs. Groovy No of line Comparison
• Java Codefor (String item : new String [] {"Rod", "Carlos", "Chris"})
{
if (item.length() <= 4)
{
System.out.println(item);
}
}
• Groovy Code
["Rod", "Carlos", "Chris"].findAll{it.size() <= 4}.each{println it}
/*A Typical Groovy Class*/
class Customer{ // properties Integer id String name Date dob
// sample code static void main(args)
{ def customer = new Customer(id:1, name:"Gromit", dob:new Date()) println("Hello ${customer.getName()}")customer.setName(“James”)println("Hello ${customer.getName()}")
} }
Java Vs. Groovy No of line Comparison
Closures• A block of code that can access variables in the scope where it is declared or
outside
• Higher order functions
• A closure will have a default parameter named it if you do not define one
def x = { println it }
• And here's how you call it (two options):
x('Hello, world!')
x.call('Hello, world')
Closure Arguments(Typed or Untyped)• Untyped Arguments
def isList = { i -> i instanceof List } if (isList([]))
{println "This is a List“
}
• Typed Arguments
def prefix = { String s -> while (s.length() < 17)
{ s = "0$s" } s // return keyword is not required } def id = prefix "1234" // parentheses are not required
Closures as arguments and Recursion• Closures can be passed as arguments
• Consider the each() method on java.util.Map: System.properties.each { println it.key }
• Recursion• lambda is annonymous
def fac =
{
int i -> i == 1 ? 1 : i * call(i - 1)
}
println fac(10)
Currying• Currying is a programming technique that transforms a function into
another while fixing one or more input values
def multiply = { x, y -> return x * y } // closuredef triple = multiply.curry(3) // triple = { y -> return 3 * y }def quadruple = multiply.curry(4) // quadruple = { y -> return 4 * y }def p = triple.call(4) // explicit calldef q = quadruple(5) // implicit callprintln "p: ${p}" // p is 12println "q: ${q}" // q is 20
Currying contd..
def lSubtract = { x, y -> return x - y }def rSubtract = { y, x -> return x - y }def dec = rSubtract.curry(1) // dec = { x -> return x - 1 }def cent = lSubtract.curry(100) // cent = { y -> return 100 - y }def p = dec.call(5) // explicit calldef q = cent(25) // implicit callprintln "p: ${p}" // p is 4println "q: ${q}" // q is 75
Variable Arguments int sum(int... someInts)
{
//ellipsis notation
def total = 0
for (int i = 0; i < someInts.size(); i++)total += someInts[i]
return total
}
assert sum(1) == 1
assert sum(1, 2) == 3
Operator Overloading ! - 1it does it by following a naming convention for methods.
Operation Method
a+b a.Plus(b)
a-b a.minus(b)
a*b a.multiply(b)
a**b a.power(b)
a/b a.div(b)
a % b a.mod(b)
a | b a.or(b)
a & b a.and(b)
Operator Overloading ! - 2
a ^ b a.xor(b)
a++ or ++a a.next()
a-- or --a a.previous()
a[b] a.getAt(b)
a[b] = c a.putAt(b, c)
a << b a.leftShift(b)
a >> b a.rightShift(b)
switch(a) { case(b) : } b.isCase(a)
~a a.bitwiseNegate()
-a a.negative()
+a a.positive()
Operator Overloading ! - 3text = "Programing" - "ing" + "er" assert "Programer" == text list = [1,2,3] list += [4,5,6] assert [1,2,3,4,5,6] == list
list << 7 // list.leftShift(7) -> list.add(7)assert [1,2,3,4,5,6,7] == list
s = "A" * 5 assert s == "AAAAA“s = "ABCDE" assert "BC" == s[1..2] s.getAt([1..2]); ranged operation assert "C" == s[2] // s.getAt(2) -> s.charAt(2)
Looping• General for loop and while loop
• Classical for loop def x = 0 for ( i in 0..9 ) //RANGE { x += i } assert x == 45 // iterate over a list
• Iterate over a list
x = 0 for ( i in [0, 1, 2, 3, 4] ) //LIST { x += i } assert x == 10
def a = [1,2,3,4,5]
a[1..-1]
OUTPUT : [2, 3, 4, 5]
def a = [1,2,3,4,5]
a[1..<-1]
OUTPUT: [2, 1]
Array Slicing
Elvis Operator• Elvis Operator alternative to ternary operator
//traditional ternary operatorString name = “Sam";String displayName = name != null ? name : "Unknown";
//elvis operatorString name = “Sam"String displayName = name ? name : "Unknown"
//eliminate DRY String name = “Sam" String displayName = name ?: "Unknown"
Agenda• Introduction to Groovy• Key Features• Closures• Operator Overloading• Array Slicing and looping
• Collections
• Dynamic Methods and Properties• Regular Expressions• File IO• Database Operations• Unified Field and Programming Languages
Collections in Groovy
– Lists
– Ranges
– Maps
– Expandos (Dynamic Objects)
Lists• Lists have been implemented in Groovy as ArrayLists which store elements of type Object.• Create a list def myList = [1,2,3.6,-9.01,“hello”,“a string”, new Date()]• Create an empty list myList = [ ]• Size of a list myList.size()• Accessing an element of list myList.get( 1 ) or myList[ 1 ] are same.• Add elements to a list myList << 0 << -1 << ‘hello’• Add a list to a list myList << [1,2] << someOtherList• New ways of adding elements to a list myList += 3; myList += [3,5]• Flattening a list of lists
[ 1, [2,3,[4,5],6], 7, [8,9] ].flatten() == [1, 2, 3, 4, 5, 6, 7, 8, 9]
• Nulls are inserted if required.list = ['a', 'b', 'z', 'e', 'u', 'v', 'g']list[8] = 'x'list == ['a', 'b', 'z', 'e', 'u', 'v', 'g', null, 'x']
Lists contd..• Closures as a way to do common updates
myList = myList.collect { it * 2 }
• Closures as a way of operations[1, 2, 3].find{ it > 1 } == 2[1, 2, 3].findAll{ it > 1 } == [2, 3]
Similar keywords are every and any.• To add all elements in a list [1,2,3,4,5,6].sum() == 21• Other operations available on a list :
– Find max. and min. elements– Use –(minus) sign to remove elements from a list.– Stack operations (push, pop) can be done on a list.– Count method gives the number of elements equal to the one passed in method call.– Sort method will sort a list in ascending order.Reverse will reverse a list.
Range• Ranges allow you to create a list of sequential values.• Ranges defined with the .. notation are inclusive, that is they contain both values.• def myRange = 5..8 This will make a range 5,6,7,8• A range can be in both orders, increasing, as well as decreasing.• They are accessed same as Lists.
example: myRange += 4..-3 makes myRange as 5,6,7,8,4,3,2,1,0,-1,-2,-3• Even characters can be added to a range. myRange += ‘a’..’d’• And same strings with different last characters can be added myRange += ‘AAB’..’AAD’. • They find their usage in loops. Example for(count in start..end)• They can be used in switch statements too. Example
switch(value){case 1..10: --------;case 11..25: -------;default: -------;}
• They can be used to create Lists[ 1, *3..5, 7, *9..<12 ] == [1,3,4,5,7,9,10,11]
Maps• Maps have been implemented in Groovy as LinkedhashMap which store elements of type
key:value. By default, Groovy takes key as a String.• Example: def myMap = [name:“Alan", likes:“bread", id:1234]• Empty map is defined as myMap = [ : ]• Values in a map are accessed using key, as usually.• Maps also act like beans so you can use the property notation to get/set items inside the
Map provided that the keys are Strings which are valid Groovy identifiers. Ex:
def map = [name:"Gromit", likes:"cheese", id:1234]
assert map.name == "Gromit"
assert map.id == 1234• Similar operations as that on Lists can be performed on Maps too.
Expandos (The Dynamic Object)• An Expando is like a Map in Groovy or an object in Javascript that do not have to have their
properties in advance. • It allows you to create dynamic objects by making use of Groovy's closure mechanisms.• An Expando is different from a map in that you can provide synthetic methods that you can
call on the object.• Example:
def player = new Expando()
player.name = "Dierk"
player.greeting = { "Hello, my name is $name" }
println player.greeting()
player.name = "Jochen"
println player.greeting()
Note: The closure has access to the properties assigned to the Expando, even though these values may change over time.
Agenda• Introduction to Groovy• Key Features• Closures• Operator Overloading• Array Slicing and looping
• Collections
• Dynamic Methods/Mixins and Properties• Regular Expressions• File IO• Database Operations• Unified Field and Programming Languages
Groovy Way of Handling…
– Dynamic Methods and Properties
– Regular Expressions
– File I/O
– Database Connectivity
Dynamic Method Invocation
• You can invoke a method even if you don't know the method name until it is invoked:class Dog
{ def bark() { println "woof!" }
def sit() { println "(sitting)" }
def jump() { println "boing!" }
}
def doAction( animal, action ){
animal."$action"() //action name is passed at invocation}
def rex = new Dog()
doAction( rex, "bark" ) //prints 'woof!‘
doAction( rex, "jump" ) //prints 'boing!'
Dynamic Methods/mixins
george = new Wombat()george.mixin("say") { something-> println something }george.say("Hello, world!")
george = new Wombat().mixin(FighterType)
william = new Wombat()
georage.getFighter() // returns william.getFighter()//error
Dynamic Properties
• You can also override property access using the getProperty and setProperty property access hooks, Dynamically
class Expandable
{
def storage = [:] //Empty MAP
def getProperty(String name) { storage[name] } //AUTO RETURN
void setProperty(String name, value) { storage[name] = value }
}
def e = new Expandable()
e.foo = "bar"
println e.foo //OUTPUT: bar
Regular Expressions• Groovy supports regular expressions natively using the ~"pattern" expression, • Which compiles a Java Pattern object from the given pattern string.• Groovy also supports the =~ (create Matcher) and ==~ (matches regex) operators.• Packages that are used in Groovy for RegEx
– import java.util.regex.Matcher– import java.util.regex.Pattern
• Regular expression support is imported from Java.
def pattern = ~/foo/
assert pattern instanceof Pattern
assert pattern.matcher("foo").matches()
def matcher = "cheesecheese" =~ /cheese/
assert matcher instanceof Matcher
answer = matcher.replaceAll("edam")
def cheese = ("cheesecheese" =~ /cheese/).replaceFirst("nice") assert cheese == "nicecheese"
Works with standard Java Reader/Writer , InputStream/OutputStream ,File and URL classes
Message Passing … Using Closures
new File("foo.txt").eachLine { line -> println(line) }
Don’t Bother about Resource Closing Mechanism Groovy Methods will handle it.
def fields = ["a":"1", "b":"2", "c":"3"]new File("Foo.txt").withWriter { out -> fields.each() { key, value ->
out.writeLine("${key}=${value}") }}
- No Reader / Writer Object HandlingHandle the resource for you via a closure - which will automatically close down any resource if an exception occurs
- No Data Piping (Stream Management)
- No Exception HandlingThe eachLine() method ensures that the file resource is correctly closed. Similarly if an exception occurs while reading, the resource will be closed too.
File Input / Output
Executing External Processes
Groovy provides a simple way to execute command line processes.def process = "ls -l".execute()process.in.eachLine { line -> println line }
====================
Process p = "cmd /c dir".execute()println "${p.text}“
====================
def initialSize = 4096def outStream = new ByteArrayOutputStream(initialSize) //STREAMSdef errStream = new ByteArrayOutputStream(initialSize) def proc = "ls.exe".execute() proc.consumeProcessOutput(outStream, errStream) proc.waitFor() println 'out:\n' + outStream println 'err:\n' + errStream
SQL can be more Groovy - 1• You can perform queries and SQL statements, passing in variables easily with
proper handling of statements, connections and exception handling.
import groovy.sql.Sql
def foo = 'cake‘
def database = Sql.newInstance( "jdbc:mysql://localhost:3306/mydb", "user",
"pswd",
"com.mysql.jdbc.Driver")
database.eachRow("select * from FOOD where type=${foo}“)
{ println "Smith likes ${it.name}" }
Thanks to closures.
SQL can be more Groovy - 2• You can perform queries and SQL statements, passing in variables easily with
proper handling of statements, connections and exception handling.
import groovy.sql.Sql
def foo = 'cheese‘
def database = Sql.newInstance( "jdbc:mysql://localhost:3306/mydb", "user",
"pswd",
"com.mysql.jdbc.Driver")
def answer = 0
sql.eachRow("select count(*) from FOOD where type=${foo}")
{ row -> answer = row[0] }
Println (“Our menu has $answer dishes to choose from!)
Thanks to closures.
SQL can be more Groovy - 3• You can perform queries and SQL statements, passing in variables easily with
proper handling of statements, connections and exception handling.
import groovy.sql.Sql
def foo = 'cheese‘
def database = Sql.newInstance( "jdbc:mysql://localhost:3306/mydb", "user",
"pswd",
"com.mysql.jdbc.Driver")
def food = database.dataSet('FOOD')
def cheese = food.findAll { it.type == 'cheese' }
cheese.each { println “${it.name} will be delicious" }
Thanks to closures.
Why to Thank Closures ?A typical JDBC Program should have these Steps 1. Loading a database driver2. Creating a oracle JDBC Connection3. Creating a JDBC Statement object4. Executing a SQL statement with the Statement object, and returning a jdbc resultSet.
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");//or any other driver } catch(Exception x){
System.out.println( "Unable to load the driver class!" ); }try {
Connection con = DriverManager.getConnection(url, userid, password);} catch(SQLException ex) {
System.err.println("SQLException: " + ex.getMessage()); }String createString="create table Employees(“+"Employee_ID INTEGER,”+"Name VARCHAR(30))";try {
stmt = con.createStatement(); stmt.executeUpdate(createString);
stmt.close();con.close();
} catch(SQLException ex) {System.err.println("SQLException: " + ex.getMessage());
}
Reduced code noise in Groovy -Simple code is beautiful code
Groovy Will Handle all those common tasks for you, - including Exception Handling, Connection - ResultSet Closing, etc..
import groovy.sql.Sql class GroovySqlExample1{
static void main(args){ database = Sql.newInstance("jdbc:mysql://localhost:3306/words",
"words", "words", "org.gjt.mm.mysql.Driver") database.eachRow("select * from word")
{ row | println row.word_id + " " + row.spelling } //CLOSURE
wid = 999spelling = "Nefarious" pospeech = "Adjective" database.execute("insert into word (word_id, spelling, part_of_speech)
values (${wid}, ${spelling}, ${pospeech})")val = database.execute("select * from word where word_id = ?", [5])//Negetive Indexing sql.eachRow("select * from word"){ grs | println "-1 = " + grs.getAt(-1) //prints part_of_speech println "2 = " + grs.getAt(2) //prints part_of_speech } }
}