Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 8 Next »

Your First Groovy

Error rendering macro 'code': Invalid value specified for parameter 'lang'
//hello.groovy
println "hello, world"
for (arg in this.args ) {
  println "Argument:" + arg;
}
// this is a comment
# this is another comment
/* this is a comment for block.you can do like this
this.args.each{ arg |
 println "hello, ${arg}"
}
*/

To run it from command line

Error rendering macro 'code': Invalid value specified for parameter 'lang'
  groovy hello.groovy MyName yourName HisName

Overview

Groovy classes compile down to Java bytecode and so there's a 1-1 mapping between a Groovy class and a Java class.
Indeed each Groovy class can be used inside normal Java code - since it is a Java class too.

Probably the easiest way to get groovy is to try working with collections. In Groovy List (java.util.List) and Map (java.util.Map) are both first class objects in the syntax. So to create a List of objects you can do the following...

Error rendering macro 'code': Invalid value specified for parameter 'lang'
list = [1, 2, 'hello', new java.util.Date()]
assert list.size() == 4
assert list.get(2) == 'hello'
assert list[2] == 'hello'

Notice that everything is an object (or that auto-boxing takes place when working with numbers). To create maps...

Error rendering macro 'code': Invalid value specified for parameter 'lang'
map = ['name':'James', 'location':'London']
assert map.size() == 2
assert map.get('name') == 'James'
assert map['name'] == 'James'

Iterating over collections is easy...

Error rendering macro 'code': Invalid value specified for parameter 'lang'
list = [1, 2, 3]
for (i in list) { println i }

Once you have some collections you can then use some of the new collection helper methods or try working with closures...

Working with closures

Closures are similar to Java's inner classes, except they are a single method which is invokable, with arbitrary parameters. A closure can have as many parameters as you wish...

Error rendering macro 'code': Invalid value specified for parameter 'lang'
closure = { param | println("hello ${param}") }
closure.call("world!")

closure = { greeting, name | println(greeting + name) }
closure.call("hello ", "world!")

If no parameter(s) is(are) specified before the | symbol then a default named parameter, called 'it' can be used. e.g.

Error rendering macro 'code': Invalid value specified for parameter 'lang'
closure = { println "hello " + it }
closure.call("world!")

Using closures allows us to process collections (arrays, maps, strings, files, SQL connections and so forth) in a clean way. e.g

Error rendering macro 'code': Invalid value specified for parameter 'lang'
[1, 2, 3].each ({ item | print "${item}-" })
["k1":"v1", "k2":"v2"].each {key, value | println key + "=" + value}

Note: If Closure is the last parameter of a method, it can be out of () if it is being defined. So, following code are all right.

Error rendering macro 'code': Invalid value specified for parameter 'lang'
def fun(int i, Closure c ) {
  c.call(i)
}

// put Closure out of ()
[1, 2, 3].each() ({ item | print "${item}-" })
fun(123) { i | println i }

// omit ()
[1, 2, 3].each ({ item | print "${item}-" })

// normal 
[1, 2, 3].each(({ item | print "${item}-" }))

closure = { i | println i}

 //[1, 2, 3].each() closure // error. closure has been defined

Here are a number of helper methods available on collections & strings...

each

iterate via a closure

Error rendering macro 'code': Invalid value specified for parameter 'lang'
[1, 2, 3].each { item | print "${item}-" }

collect

collect the return value of calling a closure on each item in a collection

Error rendering macro 'code': Invalid value specified for parameter 'lang'
value = [1, 2, 3].collect { it * 2 }
assert value == [2, 4, 6]

find

finds first item matching closure predicate

Error rendering macro 'code': Invalid value specified for parameter 'lang'
value = [1, 2, 3].find { it > 1 }
assert value == 2

findAll

finds all items matching closure predicate

Error rendering macro 'code': Invalid value specified for parameter 'lang'
value = [1, 2, 3].findAll { it > 1 }
assert value == [2, 3]

inject

allows you to pass a value into the first iteration and then pass the result of that iteration into the next iteration and so on. This is ideal for counting and other forms of processing

Error rendering macro 'code': Invalid value specified for parameter 'lang'
value = [1, 2, 3].inject('counting: ') { str, item | str + item }
assert value == "counting: 123"

value = [1, 2, 3].inject(0) { count, item | count + item }
assert value == 6

In addition there's 2 new methods for doing boolean logic on some collection...

every

returns true if all items match the closure predicate

Error rendering macro 'code': Invalid value specified for parameter 'lang'
value = [1, 2, 3].every { it < 5 }
assert value

value = [1, 2, 3].every { item | item < 3 }
assert ! value

any

returns true if any item match the closure predicate

Error rendering macro 'code': Invalid value specified for parameter 'lang'
value = [1, 2, 3].any { it > 2 }
assert value

value = [1, 2, 3].any { item | item > 3 }
assert value == false

Other helper methods include:

max / min

returns the max/min values of the collection - for Comparable objects

Error rendering macro 'code': Invalid value specified for parameter 'lang'
value = [9, 4, 2, 10, 5].max()
assert value == 10
value = [9, 4, 2, 10, 5].min()
assert value == 2
value = ['x', 'y', 'a', 'z'].min()
assert value == 'a'

join

concatenates the values of the collection together with a string value

Error rendering macro 'code': Invalid value specified for parameter 'lang'
value = [1, 2, 3].join('-')
assert value == '1-2-3'

Also the 'yield' style of creating iterators, available in Python and Ruby via the yield statement, is available. The only difference is rather than using a yield statement, we're just using closures.

Error rendering macro 'code': Invalid value specified for parameter 'lang'
class Foo {
  myGenerator(Closure yield) {
    yield.call("A")
    yield.call("B")
    yield.call("C")
  }
  
  static void main(args) {
    foo = new Foo()
	for (x in foo.myGenerator) {
   	  println x
	}
  }
}

foo = new Foo()
for (x in foo.myGenerator) {
  print("${x}-")
}

outputs
A-B-C-

The use of Closure in the method prototype is optional. If we have syntax sugar for invoking closures as if they are method calls, then the generator method could look even more like the python/ruby equivalent. Especially if parentheses are optional...

Error rendering macro 'code': Invalid value specified for parameter 'lang'
class Foo {
  myGenerator(yield) {
    yield "A"
    yield "B"
    yield("C") 
  }
  
  static void main(args) {
    foo = new Foo()
    foo.myGenerator { println "Called with ${it}" }
  }
}
  • No labels