© Adam L. Davis 2016

Adam L. Davis, Learning Groovy, 10.1007/978-1-4842-2117-4_4

4. GDK

Adam L. Davis

(1)New York, USA

The GDK (Groovy Development Kit ) provides a number of helper methods, helper operators, utilities, and additional classes.

Some of these are methods added to every Java class, like each, and some are more obscure.

Collections

Groovy adds tons of helpful methods that allow easier manipulation of collections:

  • sort—Sorts the collection (if it is sortable).

  • findAll—Finds all elements that match a closure.

  • collect—An iterator that builds a new collection.

  • inject—Loops through the values and returns a single value.

  • each—Iterates through the values using the given closure.

  • eachWithIndex—Iterates through with two parameters: a value and an index.

  • find – Finds the first element that matches a closure.

  • findIndexOf—Finds the first element that matches a closure and returns its index.

  • any—True if any element returns true for the closure.

  • every—True if all elements return true for the closure.

  • reverse—Reverses the ordering of elements in a list.

  • first—Gets the first element of a list.

  • last—Returns the last element of a list.

  • tail—Returns all elements except the first element of a list.

Spread

The spread operator can be used to access the property of every element in a collection. It can be used instead of collect in many cases. For example, you could print the name of every dragon in a list named dragons:

1   dragons*.name.each { println it }

GPath

GPath is something like XPath in Groovy. Thanks to the support of property notation for both lists and maps, Groovy provides syntactic sugar making it really easy to deal with nested collections, as illustrated in the following examples:

1   def  listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22]]
2   assert listOfMaps.a == [11, 21] //GPath notation
3   assert listOfMaps*.a == [11, 21] //spread dot notation
4   
5   listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22], null]
6   assert  listOfMaps*.a == [11, 21, null] // caters  for  null  values
7   assert listOfMaps*.a == listOfMaps.collect { it?.a } //equivalent  notation
8   // But this will only collect non-null values
9   assert listOfMaps.a == [11,21]

IO

The GDK helps you a lot with input/output (IO) .

Files

The GDK adds several methods to the File class to ease reading and writing files.

1   println path.toFile().text

A getText() method is added to the File class, which simply reads the whole file.

1   new  File("books.txt").text = "Modern Java"

Here we are using the setText method on the File class, which simply writes the file contents. For binary files, you can also use the bytes property on File:

1   byte[] data = new   File('data').bytes
2   new  File('out').bytes = data

If you want to use an InputStream or reader or the corresponding OutputStream or writer for output, you have the following methods:

1   new File('dragons.txt').withInputStream {in -> }
2   new  File('dragons.txt').withReader {r -> }
3   new  File('dragons.txt').withOutputStream {out ->}
4   new  File('dragons.txt').withWriter {w -> }

Lastly you can use the eachLine method to read each line of a file. For example:

1   new  File('dragons.txt').eachLine { line->
2   println "$line"
3   }
4   //OR
5   new  File('dragons.txt').eachLine { line, num ->
6   println "Line $num: $line"
7   }

In all of these cases, Groovy takes care of closing the I/O resource even if an exception is thrown.

A426440_1_En_4_Figa_HTML.jpg Tip

Print out a multiline file and then read it back in and print out the lines.

URLs

The GDK makes it extremely simple to execute a URL .

The following Java code opens an HTTP connection on the given URL ( http://google.com in this case), reads the data into a byte array, and prints out the resulting text.

 1   URL url = new  URL("http://google.com");
 2   InputStream input = (InputStream) url.getContent();
 3   ByteArrayOutputStream out = new  ByteArrayOutputStream();
 4   int n = 0;
 5   byte[] arr = new  byte[1024];
 6   
 7   while  (-1 != (n = input.read(arr)))
 8   out.write(arr, 0, n);
 9   
10   System.out.println(new String(out.toByteArray()));

However, in Groovy this also can be reduced to one line (leaving out exceptions):

1   println "http://google.com".toURL().text

A toURL() method is added to the String class and a getText() method (which is called as .text) is added to the URL class in Groovy.

A426440_1_En_4_Figa_HTML.jpg Exercise

Use Groovy to download your favorite web site and see if you can parse something from it.

Ranges

The Range is a built-in type in Groovy. It can be used to perform loops, in switch cases, extracting substrings, and other places. Ranges are generally defined using the syntax start..end.

Ranges come in handy for traversing using the each method and for loops:

1   (1..4).each {print it} //1234          
2   for (i in 1..4) print i //1234

A case statement was demonstrated in an earlier chapter such as the following:

1   case  12..30: // Range  12  to  30          
A426440_1_En_4_Figb_HTML.jpg Warning

This works only if the value given to the switch statement is the same type as Range (an integer in this case).

You can use ranges to extract substrings from a string using the getAt syntax. For example :

1   def  text = 'learning groovy'
2   println text[0..4] //learn
3   println text[0..4,8..-1] //learn groovy
A426440_1_En_4_Figc_HTML.jpg Tip

Negative numbers count down from the last element of a collection or string. So -1 equates to the last element.

You can also use ranges to access elements of a list:

1   def list = ['hank', 'john', 'fred']
2   println list[0..1] //[hank, john]

You can define a range to be exclusive of the last number by using the ..< operator. For example, another way to print 1234 would be the following:

1   (1..<5).each {print it} //1234          
A426440_1_En_4_Figa_HTML.jpg Exercsie

Attempt to use a variable in a range. Do you need to surround the variable with parentheses?

Utilities

The GDK adds several utility classes such as ConfigSlurper, Expando, and ObservableList/Map/Set.

ConfigSlurper

ConfigSlurper is a utility class for reading configuration files defined in the form of Groovy scripts. Like with Java *.properties files, ConfigSlurper allows for a dot notation. It also allows for nested (closure) configuration values and arbitrary object types.

 1   def config = new ConfigSlurper().parse('''
 2       app.date = new Date()
 3       app.age  = 42
 4       app {
 5           name = "Test${42}"
 6       }
 7   ''')
 8   
 9   def properties = config.toProperties()
10   
11   assert properties."app.date" instanceof String
12   assert properties."app.age" == '42'
13   assert properties."app.name" == 'Test42'

Expando

The Expando class can be used to create a dynamically expandable object. You can add fields and methods. This can be useful when you want to use extremely dynamic meta-programming. For example:

1   def  expando = new  Expando()
2   expando.name = { -> 'Draco' }
3   expando.say = { String s -> "${expando.name} says: ${s}" }
4   expando.say('hello') // Draco says: hello
A426440_1_En_4_Figa_HTML.jpg Exercise

Use meta-programming to alter some class’s metaClass and then print out the class of the metaClass. Is it the Expando class?

ObservableList/Map/Set

Groovy comes with observable lists, maps, and sets. Each of these collections triggers PropertyChangeEvent (from the java.beans package) when elements are added, removed, or changed. Note that a PropertyChangeEvent does not only signal that an event has occurred, it also holds information on the property name and the old/new value of a property.

For example, here’s an example using ObservableList and printing out the class of each event:

1   def  list = new  ObservableList()
2   def printer = {e -> println e.class}
3   list.addPropertyChangeListener(printer)
4   list.add 'Harry Potter'
5   list.add 'Hermione Granger'
6   list.remove(0)
7   println list

This would result in the following output:

1   class    groovy.util.ObservableList$ElementAddedEvent
2   class java.beans.PropertyChangeEvent
3   class    groovy.util.ObservableList$ElementAddedEvent
4   class java.beans.PropertyChangeEvent
5   class    groovy.util.ObservableList$ElementRemovedEvent
6   class java.beans.PropertyChangeEvent
7   [Hermione Granger]

This can be useful for using the Observer pattern on collections.

A426440_1_En_4_Figa_HTML.jpg Exercise

Use an ObservableMap and a PropertyChangeListener to reject null values from being added to the map .

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.34.226