JAVA7新特性1---groovy

转载一篇groovy官方的使用文档

Groovy with Eclipse - Tutorial

Lars Vogel

Version 2.2

29.01.2015

Groovy

This article gives a short overview of the Groovy language including collections, loops, gstrings, MOP, closures, operator overloading, XML handing and using Groovy together with Java class. It also describes how to use the Eclipse IDE for developing Groovy.

This article assumes that you have already Eclipse installed and that you have used Eclipse for Java development. This article was written using Groovy 2.4, Eclipse 4.4 (Luna) and Java 1.8.


Table of Contents

1. Groovy
1.1. What is Groovy? 1.2. Groovy classes and scripts 1.3. Compatibility with Java 1.4. Reasons to use Groovy 1.5. Imports in Groovy
2. Installation of Groovy
2.1. Install Groovy for the command line 2.2. Installation of the Groovy tools for the Eclipse IDE 2.3. Installation of the Groovy tools for the IntelliJ IDE
3. Using Groovy without IDE support
3.1. Options for using Groovy with IDE support 3.2. The Groovy Console 3.3. The Groovy shell 3.4. Using the Groovy compiler to create class files
4. Exercise: Create a Groovy program with the Eclipse IDE
4.1. Target of this exercise 4.2. Create a new Groovy project 4.3. Run the Groovy class 4.4. Validate the Groovy class
5. Groovy classes, objects and methods
5.1. A Groovy class and default access modifier 5.2. Groovy objects (Plain Old Groovy Objects) and fields 5.3. Constructors 5.4. Equals, == and the method is() 5.5. Optional parameters in methods 5.6. Default parameters in methods
6. GPath 7. Groovy data types
7.1. Optional typed variables 7.2. Groovy and generics 7.3. All types are objects 7.4. Numbers 7.5. Ranges
8. Operator overloading 9. Strings in Groovy
9.1. Strings and GStrings 9.2. Operator overloading in Strings
10.
10.1. Regular expressions
11. Lists
11.1. Defining and accessing lists 11.2. Convert a list to an array and vice versa 11.3. List methods 11.4. Operator overloading in Lists 11.5. Spreaddot operator 11.6. Searching in a list with find, findall and grp
12. Maps in Groovy
12.1. Map declaration and access 12.2. Each, any and the every method 12.3. Searching in a map 12.4. Getting and adding defaults values via the get method 12.5. Named arguments for method invocation 12.6. Convert a list to a map
13. Control structures
13.1. Groovy evaluation of conditions - The Groovy truth 13.2. if statements 13.3. switch statement and the isCase method 13.4. Safe navigation operator 13.5. Elvis operator
14. Loops
14.1. For and while loops 14.2. Using the each method 14.3. Iterative with numbers
15. Using lambdas and closures in Groovy
15.1. Defining closures 15.2. Defining default values in a closure 15.3. Example: Using closures in the each method 15.4. Example: Sort a list by lenght of the string 15.5. Using the with method
16. Groovy and concurrency 17. File and network I/O with Groovy
17.1. Groovy and processing files 17.2. Writing to files 17.3. Groovy and processing HTTP get requests
18. Using template engines in Groovy 19. Groovy builders 20. Groovy and Markup like XML or HTML
20.1. Parsing XML with XmlSlurper 20.2. Using the MarkupTemplateEngine to generated Markup 20.3. Creating Markup (XML) files with the MarkupBuilder
21. Groovy and JSON 22. Compile-time meta programming and AST transformations
22.1. What are AST transformations? 22.2. @TupleConstructor 22.3. @EqualsAndHashCode 22.4. @ToString for beans 22.5. @Canonical 22.6. @Immutable for immutable Java beans 22.7. @Delegate 22.8. @Sortable for beans 22.9. @Memoize for methods 22.10. @AnnotationCollector for combining AST Transformations annotations 22.11. @Bindable observable Properties 22.12. @Builder 22.13. @Grab for dependency management 22.14. Other AST Transformations 22.15. Writing custom transformations
23. Meta Object Protocol
23.1. What is the Meta Object Protocol_ 23.2. Calling methods or accessing properties on a Groovy object 23.3. Adding methods and properties
24. Exercise: Meta Object Protocol
24.1. Target of this exercise 24.2. Making a Groovy object responding to all methods and property calls 24.3. Exercise: Adding JSON output to Groovy class, the ugly and the smart way 24.4. Exercise: Adding a method to String
25. Using Groovy classes in Java
25.1. Calling Groovy classes directly 25.2. Calling a script
26. Using Groovy in a Maven or Gradle build
26.1. Using Groovy in a Maven build 26.2. Using Groovy in a Gradle build
27. About this website 28. Links and Literature
28.1. Groovy Links 28.2. vogella GmbH training and consulting support

1. Groovy

1.1. What is Groovy?

Groovy is an optionally typed, dynamic language that runs on the JVM. It is tightly integrated with the Java programming language. Groovy describes itself as feature-rich and Java-friendly language.

Groovy source code is compiled into Java byte-code by the Groovy compiler. To run Groovy code in a Java virtual machine, only the Groovy JAR file must be present in the classpath at runtime.

Groovy supports standard Java constructs including annotations, generics, static imports, enums, varargs and lambda expression. It provides lots of simplifications compared to the Java programming language and advanced language features as properties, closures, dynamic methods, the Meta Object Protocol (MOP), native support for lists, maps, regular expressions, duck typing and the elvis operator.

1.2. Groovy classes and scripts

A Groovy source files ends with the .groovy extension. This file can contain a Groovy script or a Groovy class. A Groovy script is a code listing which does not include a class definition. Groovy scripts are converted at compile time to a class which extends the groovy.lang.Script class.

The classical "Hello world" program can be written as a short Groovy script.

println 'Hello World' 

1.3. Compatibility with Java

Groovy runs inside the JVM and can use Java libraries. Every Groovy type is a subclass of java.lang.Object.

Groovy code can call Java code and Java code can call Groovy code. Every Groovy class is compiled into a Java class and you can use the new operator in Java to create instances of the Groovy class. This instance can be used to call methods or to pass as parameter to a fitting Java method. Groovy classes can extend Java classes and Java classes can also extend Groovy classes.

Groovy is almost compatible with the Java 7 sytax, e.g., almost every valid Java 7 construct is valid Groovy code. This makes the migration to Groovy for a Java programmer relatively smooth.

Groovy does currently not support Java 8 lambda expressions.

1.4. Reasons to use Groovy

Groovy focus on simplicity and ease of use as its leading principle. This makes using Groovy very productive.

The enhancements of Groovy compared to Java can be classified as:

  • Groovy language features

  • Groovy specific libraries

  • Additional methods to existing Java classes by the Groovy Developer Kit, this is commonly known as the Groovy JDK.

The following list contains some of the example how Groovy archives this.

  • Simplification - Groovy does not require semicolons at the end of statements. The return keyword can be left out, by default Groovy returns the last expression of the method, top level parentheses can be left out, the public keyword can be left out, it is the default in Groovy. It also allows optional typing.

  • Flexibility - Groovy allows to change classes and methods at runtime, e.g. if a method is called which does not exist on a class, the class can intercept this call and react to it. This allows for example that Groovy provides a very flexible builder pattern.

  • Ease of use - Groovy has list, maps and regular expressions directly build into the language.

  • Simplification in I/O - parsing and creating XML, JSON and files is very simple with Groovy.

1.5. Imports in Groovy

Groovy automatically imports the following packages and classes which can be used in Groovy without specifying the package name.

  • groovy.lang.*

  • groovy.util.*

  • java.lang.*

  • java.util.*

  • java.net.*

  • java.io.*

  • java.math.BigInteger

  • java.math.BigDecimal

Groovy allows that an import is shortened for later access, e.g., import javax.swing.WindowConstants as WC.

2. Installation of Groovy

2.1. Install Groovy for the command line

To be able to run Groovy code from the command line download the latest version from Groovy from the Groovy download website.

Download at least the binary zip file and extract it to a directory on your hard disk. Afterwards set the GROOVY_HOME environment variable and %GROOVY_HOME%/bin to your path.

If you are using MS Windows you can use the Windows installer. This installer configured the environment variables automatically for you.

Download Groovz command line

2.2. Installation of the Groovy tools for the Eclipse IDE

You can download a pre-configured version of the Eclipse IDE with Groovy and Gradle support from the following website: Spring tools download side.

Alternatively you can also install the Groovy tooling into an existing Eclipse installation. Open the Eclipse Update manager via the HelpInstall New Software... menu entry to install the Groovy Eclipse plug-in. Enter the following URL in this dialog:

http://dist.springsource.org/snapshot/GRECLIPSE/e4.5/ 

Install Groovy support for Eclipse

The update site is Eclipse version dependent, see Groovy/Grails Tool Suite™ Downloads if you use a different release than Eclipse 4.5.

2.3. Installation of the Groovy tools for the IntelliJ IDE

You can also download the IntelliJ IDEA Community edition for free which includes support for Groovy.

3. Using Groovy without IDE support

3.1. Options for using Groovy with IDE support

You can execute a Groovy class or script from your IDE but Groovy provides other options. You can run Groovy code via:

  • the Groovy shell: groovysh

  • the Groovy interpreter: groovy

  • the Groovy Console : groovyConsole

  • complile Groovy code to classfiles and run it via the Java virtual machine

3.2. The Groovy Console

Start the interactive Groovy Shell with the command groovyConsole. This console allows you to test Groovy code.

3.3. The Groovy shell

The Groovy shell is the simplest way to run Groovy program. The groovy shell allow you to type in groovy commands and let them evaluate.

Open a command shell (Start-> Run -> cmd under Windows) and start the groovy shell via "groovysh". Type in the following code:

println("Hello Groovy") 

Press enter-> the system will execute your code.

3.4. Using the Groovy compiler to create class files

You can also complile Groovy code into Java bytecode to use it from Java. To use the byte code the Groovy runtime library must included in the Java classpath.

To create Java bytecode, run the groovyc Hello.groovy command.

4. Exercise: Create a Groovy program with the Eclipse IDE

4.1. Target of this exercise

In this exercise you learn how to create Groovy program with the Eclipse IDE.

4.2. Create a new Groovy project

The following example assumes you have Groovy and the Eclipse IDE installed and configured.

Create a new Groovy project called com.vogella.groovy.first the FileNew OtherGroovy Groovy Project.

Creating a Groovy project

Creating a Groovy project

After entering the project name, press the Finish button. This creates a new Groovy project similar to a new Java project but with the required Groovy libraries.

Creating a Groovy project

Right click on the source folder and New Package from the context menu. Create a new package called first.

Create a new Groovy class called FirstGroovy via FileNewOtherGroovyGroovy Class.

Creating a Groovy class Part 1

Create the following code.

package first

class FirstGroovy {
  
  static void main(def args){
    def mylist= [1,2,"Lars","4"]
    mylist.each{ println it }
  }
} 

4.3. Run the Groovy class

Right-click the Groovy class, and select Run AsGroovy Script from the context menu.

4.4. Validate the Groovy class

The above menu entry triggers the execution of the main method in your Groovy class and prints output to Console view of the Eclipse IDE.

Congratulation! You created and ran your first Groovy class.

5. Groovy classes, objects and methods

5.1. A Groovy class and default access modifier

A Groovy class is defined with the class keyword, similar to Java. All Groovy classes and methods are by default public.

The following is an example Groovy class called Task.groovy.

package com.vogella.groovy.first

class Task {
  String summary
  String description
  Date dueDate
} 

5.2. Groovy objects (Plain Old Groovy Objects) and fields

In Groovy all fields of a class have by default the private access modifier. Groovy creates automatically getter and setter methods for the fields. If you annotate the class or a property with the @Bindable annotation, Groovy also adds PropertyChangeSupport to the class or property. Such a Groovy classes fits to the Java beans specification.

Groovy objects are frequently referred to as Plain Old Groovy Objects (POGO).

You can use the getter and setter directly or use the name of the field for access. Groovy also supports the array subscript acessor (object[property]). Groovy uses the getter or setter method, even if you directly use the name of the field. If a field should not be changeable define it as final, in this case Groovy will not provide a setter.

5.3. Constructors

Groovy provides constructors with named parameters in which you can specify the element you would like to set during construction. This constructor is also called map based constructor, as it uses the property:value map syntax.

If such a constructor is used, Groovy calls the default constructor and then calls the setter methods for the attributes. This "constructor with named parameters" works also if you call a Java class from Groovy code as Groovy uses again the default constructor of the Java class and then the methods to set the properties.

The usage of the constructors with named parameters is demonstrated by the following example.

package com.vogella.groovy.first

public class Person{
  String firstName
  String lastName
  int age
  def address
  
  static void main(def args) {
    Person p = new Person()
    // use the generated access methods
    p.setFirstName("Lars")
    // this will still use the generated access method, it is not a direct access!
    p.lastName = "Vogel" 
    p.address = ("Homestreet 3");
    println(p.firstName + " " + p.lastName);
    // use the generated constructor
    p = new Person(firstName: "Peter", lastName:"Mueller");
    println(p.firstName + " " + p.lastName);
  }
  
} 

5.4. Equals, == and the method is()

One difference between Java and Groovy is that the == operator will check for equality and not for identity. Java checks if both variables points to the same object while Groovy checks if both variables are equals. To check for identify you can use in Groovy the is() method.

In Groovy null == null returns true. If two references point to the same object it is also true. If an object implements the compareTo method, Comparable this method is used, otherwise the equals method.

5.5. Optional parameters in methods

Groovy allows to have optional parameter values. Optional parameter values are indicated by =0.

class Hello {

static main(args){
  println sum(1,5)
  println sum(1,2,5)
  }

static sum(a,b,c=0){
  a+b+c;
  }
} 

5.6. Default parameters in methods

In Groovy you assign default values to parameters in a method. If a default value for a parameter is defined, Groovy offers two method signatures: one with all parameters and one where the parameter with a default value is omitted. If you use multiple parameters with default values then the right most parameter with a default value is first eliminated then the next, etc.

6. GPath

GPath is a path expression language integrated into Groovy which allows parts of nested structured data to be identified. In this sense, it has similar aims and scope as XPath does for XML. The two main places where you use GPath expressions is when dealing with nested POJOs or when dealing with XML.

For example the a.b.c statement is equivalent to a.getB().getC().

GPath navigation works also in complex structures like XML or JSON.

7. Groovy data types

7.1. Optional typed variables

Variables and fields can be typed as in Java or your can use the def keyword to define a variable. As a rule of thumb, use the type if it adds clarity to your code otherwise use def.

// valid variable definitions

// typed
String name
int x
Integer y

// untyped
def list
def map
def todo 

At runtime variables and fields are always typed, Groovy infers the type based on your source code. This means that at runtime you receive an error if you try to assign a non fitting type to a variable.

Variables which are not declared can be used in Groovy scripts to indicate that they can be set from outside. Such declarations are only valid in scripts and become part of the scripts binding.

7.2. Groovy and generics

Groovy supports the syntax of generics but does not enforce it. For example, you can put any type into a List<Integer> collection. To enforce type checking in Groovy you can use AST transformations. See Section 22, “Compile-time meta programming and AST transformations” to learn more about AST transformations.

7.3. All types are objects

All variables in Groovy are objects (reference variables), Groovy does not use primitive variables. Groovy still allows to use the primitives types as a short form for the variable declaration but the compiler translates this into the object.

7.4. Numbers

Numbers are objects in Groovy, as well as variables defined as int, float, double, etc. If you use numbers in your code Groovy assigns a type to it and performs automatically the down- and upcasting for you.

As numbers are object they have also methods for example the times method which executes a block of code the number of times defined by the number.

Create the following class called TypesTest to play with numbers.

package example

int i = 1 // Short form for Integer i = new Integer(1)
int j = i +3
int k = i.plus(3) // Same as above
// Make sure this worked
assert(k==4)
println i.class
println j.class
println k.class

// Automatic type assignement
def value = 1.0F
println value.class
def value2 = 1
println value2.class
// this would be zero in Java
value2 = value2 / 2
println value2
// value was upcasted
println value2.class

10.times {println "Test"} 

The operators, like + or - are also mapped to methods by Groovy.

Table 1. 

OperatorNameMethod
a+bplusa.plus(b)
a-bminusa.minus(b)
a*bstara.multiply(b)
a/bdividea.div(b)
a%bmoduloa.mod(b)
a--, --adecrementa.previous()
a++, ++aincrementa.next()
a**bpowera.power(b)
a-bminusa.minus(b)
a-bminusa.minus(b)


7.5. Ranges

Groovy supports the Range data type is a Collection. Ranges consists of two values separated by two dots. Ranges can for example be used to define a loop statement.

package de.vogella.groovy.datatypes

for (i in 0..9) {
  println ("Hello $i")
}
assert 'B'..'E' == ['B', 'C', 'D', 'E'] 

You can use Strings for the definition of ranges, these ranges follow the alphabet.

Every object can be used as Range long as it implements the previous() and next() methods and the java.util.Comparable interface. The methods map to the ++ and -- operators.

8. Operator overloading

Groovy supports that you can use the standard operations in your own classes. For example if you want to use the operation a+b where a and b are from class Z then you have to implement the method plus(Zname) in class Z.

9. Strings in Groovy

9.1. Strings and GStrings

Groovy allows to use two different types of String, the java.lang.String and the groovy.lang.GString class. You can also define a single line or a multi-line string in Groovy.

Strings which are quoted in by "" are of type GString (short for Groovy Strings). In GStrings you can directly use variables or call Groovy code. The Groovy runtime evaluates the variables and method calls. An instance of GString is automatically converted to a java.lang.String whenever needed.

package com.vogella.groovy.strings

def name = "John"
def s1 = "Hello $name" // $name will be replaced
def s2 = 'Hello $name' // $name will not be replaced
println s1
println s2
println s1.class
println s2.class

// demonstrates object references and method calls
def date = new Date()
println "We met at $date"
println "We met at ${date.format('MM/dd/yy')}" 

The definition of these different types of Strings is demonstrated in the following table.

Table 2. Define Strings in Groovy

String exampleDescription
'This is a String'Standard Java String
"This is a GString"Groovy GString, allows variable substitution and method calls
''' Multiline string (with line breaks)'''A multi line string
""" Multiline string (with line breaks)"""A multi line GString
/regularexpression/Forward Slash – Escape backslashes ignored, makes Regular Expressions more readable


The tokenize() method tokenize the String into a list of String with a whitespace as the delimiter.

The Groovy JDK adds the toURL() method to String, which allows to convert a String to a URL.

The trim method removes is applied to remove leading and trailing whitespace.

9.2. Operator overloading in Strings

String support operator overloading. You can use + to concatenate strings, - to substract strings and the left-shift operator to add to a String.

10.1. Regular expressions

Groovy is based on Java regular expression support and add the addition support operators to make the usage of regular expressions easier.

Groovy adds the Slashy string as String declaration. Slashy strings are Strings between two "/" signs. They don't need escape backslashes in regular expressions.

Table 3. 

ConstructDescription
str =~ patternCreates a Matcher from a regex and a string. Same as Pattern.compile(pattern).matcher(str). If you call the find method it returns true if the pattern is contained in the str variable.
==~Returns a boolean if pattern matches str. Same as Pattern.matches(pattern, str).
~StringCreates a Pattern object from a string. Equivalent to Pattern.compile(str) in Java.


If you use the ~ operator such a string turns into a regular expression which can be used for pattern matching. You can use special sign (escape characters) in Strings if you put them between slashes.

package de.vogella.groovy.datatypes

public class RegularExpressionTest{
  public static void main(String[] args) {
    // Defines a string with special signs
    def text = "John Jimbo jingeled happily ever after"
    
    // Every word must be followed by a nonword character
    // Match
    if (text==~/(\w*\W+)*/){
      println "Match was successful"
    } else {
      println "Match was not successful"
    }
    // Every word must be followed by a nonword character
    // Find
    if (text=~/(\w*\W+)*/){
      println "Find was successful"
    } else {
      println "Find was not successful"
    }
    
    if (text==~/^J.*/){
      println "There was a match"
    } else {
      println "No match found"
    }
    def newText = text.replaceAll(/\w+/, "hubba")
    println newText
  }
  
  
} 

Groovy also provides the replaceAll method, which allows to define a closure for the replacement.

11. Lists

11.1. Defining and accessing lists

Groovy treads lists as first class constructs in the language. You define a list via List list = new List[]. You can also use generics. To access element i in a list you can either use list.get(i) or list[i].

package de.vogella.groovy.datatypes

public class Person{
  String firstName;
  String lastName;
  Person(String firstName, String lastName){
    this.firstName = firstName
    this.lastName= lastName
  }
} 

package de.vogella.groovy.datatypes

public class ListMapTest{

  public static void main(args){
    List<Integer> list = [1,2,3,4]
    println list[0]
    println list[1]
    println list[2]
    List<Person> persons = list[]
    Person p = new Person("Jim", "Knopf")
    persons[0] = p
    println persons.size()
    println persons[0].firstName
    println persons.get(0).firstName
  }
} 

Groovy allows direct property access for a list of items. This is demonstrated by the following snippet.

package de.vogella.groovy.datatypes

public class ListMapTest{

  public static void main(args){
    List<Person> persons = list[]
    persons[0] = new Person("Jim", "Knopf")
    persons[1] = new Person("Test", "Test")
    println persons.firstName
  }
} 

11.2. Convert a list to an array and vice versa

Groovy converts automatically an Array to a List and vice versa. This is demonstrated by the following snippet.

package list

// demo of auto conversion
def String[] strings = "This is a long sentence".split();
// convert Array to list
def List listStrings = strings
// convert List back to Array
def String[] arrayStrings = listStrings

println strings.class.name
println listStrings.class.name
println arrayStrings.class.name 

11.3. List methods

The following lists the most useful methods on List.

  • reverse()

  • sort()

  • remove(index)

  • findAll{closure} - returns all list elements for which the closure validates to true

  • first()

  • last()

  • max()

  • min()

  • join("string") - combines all list elements, calling the toString method and using the string for concatenation.

  • << e - appends element e to the list

The grep method can be used to filter elements in a collection.

11.4. Operator overloading in Lists

List support operator overloading. You can use + to concatenate strings, - to substract lists and the left-shift operator to add elements to a list.

11.5. Spreaddot operator

The spread dot operator (spread-dot operator) *. is used to invoke a method on all members of a Collection. The result of this operation is another Collection object.

def list = ["Hello", "Test", "Lars"]

// calculate the length of every String in the list
def sizeList = list*.size()
assert sizeList = [5, 4, 4] 

11.6. Searching in a list with find, findall and grp

You can search in a list.

  • findAll{closure} - returns all list elements for which the closure validates to true

  • find{closure} - returns the list element for which the closure validates to true

  • grep(Object filter) - Iterates over the collection of items and returns each item that matches the given filter - calling the Object#isCase. This method can be used with different kinds of filters like regular expressions, classes, ranges etc.

package list

def l1 = ['test', 12, 20, true]
// check with grep that one element is a Boolean
assert [true] == l1.grep(Boolean)

// grep for all elements which start with a pattern
assert ['Groovy'] == ['test', 'Groovy', 'Java'].grep(~/^G.*/)

// grep for if the list contains b and c
assert ['b', 'c'] == ['a', 'b', 'c', 'd'].grep(['b', 'c'])

// grep for elements which are contained in the range
assert [14, 16] == [5, 14, 16, 75, 12].grep(13..17)

// grep for elements which are equal to 42.031
assert [42.031] == [15, 'Peter', 42.031, 42.032].grep(42.031)

// grep for elements which are larger than 40 based on the closure
assert [50, 100, 300] == [10, 12, 30, 50, 100, 300].grep({ it > 40 }) 

12. Maps in Groovy

12.1. Map declaration and access

Groovy treads maps as first class constructs in the language.

The items of maps are key–value pairs that are delimited by colons. An empty map can be created via [:]. By default a map is of the java.util.HashMap type. If the keys are of type String, you can avoid the single or double quotes in the map declaration.

package com.vogella.groovy.maps

class Main {

  static main(args) {
    // create map
    def map = ["Jim":"Knopf", "Thomas":"Edison"]
    // the dot operator is overloaded to access the value
    map.AnotherKey="Testing"
    // create map without quotes for the keys
    def anotherMap = [Jim:"Knopf", Thomas:"Edison"]
    // size is used to determine the number of elements
    assert create.size() == 2
    
    // if key should be evaluated put it into brackets
    def x ="a"
    // not true, as x is interpreted as "x"
    println ([a:1]==[x:1])
    // force Groovy to see x as expression
    println ([a:1]==[(x):1])

    // create empty map
    def emptyMap = [:]
    
    

  }

} 

The values of a mapped value can get accessed via map[key]. Assignment can be done via map[key]=value. You can also call get(key) or get(key,default). In the second case, if the key is not found and the default is returned, the (key,default) pair is added to the map.

package com.vogella.groovy.maps

class Main {

  static main(args) {
    // create map
    def map = ["Jim":"Knopf", "Thomas":"Edison"]
    // the dot operator is overloaded to access the value
    map.AnotherKey="Testing"
    // create map without quotes for the keys
    def anotherMap = [Jim:"Knopf", Thomas:"Edison"]
    // size is used to determine the number of elements
    assert create.size() == 2
    
    // if key should be evaluated put it into brackets
    def x ="a"
    // not true, as x is interpreted as "x"
    println ([a:1]==[x:1])
    // force Groovy to see x as expression
    println ([a:1]==[(x):1])

    // create empty map
    def emptyMap = [:]
    
    

  }

} 

The keySet() method returns a set of keys, a collection without duplicate entries and no guaranteed ordering.

12.2. Each, any and the every method

You can call closures on the elements, via the each(), any() and every() method. The any() and every() methods return a boolean depending whether any or every entry in the map satisfies a condition defined by a closure.

package com.vogella.groovy.maps

class CallMethods {

  static main(args) {
    def mymap = [1:"Jim Knopf", 2:"Thomas Edison", 3:"Lars Vogel"]
    mymap.each {entry -> println (entry.key > 1)}
    mymap.each {entry -> println (entry.value.contains("o"))}
    println "Lars contained:" + mymap.any {entry -> entry.value.contains("Lars")}
    println "Every key small than 4:" + mymap.every {entry -> entry.key < 4}

    def result =''
    for (key in mymap.keySet()) {
      result += key
    }
    println result

    mymap.each { key, value ->
      print key + " "
      println value
    }

    mymap.each { entry ->
      print entry.key + " "
      println entry.value
    }
  }
} 

As you can see in the above example you can iterate in different ways through a map. The parameter for each can by one parameter and than it is the map entry or two in which case it is the key, value combination.

12.3. Searching in a map

You can also use the following methods:

  • findAll(closure) - Finds all entries satisfying the condition defined by the closure

  • find(closure) - Find the first entry satisfying the condition defined by the closure

  • collect(closure) - Returns a list based on the map with the values returned by the closure

  • submap('key1', 'key2',) - returns a map based on the entries of the listed keys

12.4. Getting and adding defaults values via the get method

The get(key, default_value) allows to add the "default_value" to the map and return it to the caller, if the element identified by "key" is not found in the map. The get(key) method, does not add automatically to the map.

12.5. Named arguments for method invocation

It is possible to use named arguments in method invocation.

package namedarguments

def address = new Address(street: 'Reeperbahn', city: 'Hamburg')
def p = new Person(name: 'Lars', address: address, phoneNumber: '123456789')

// Groovy translates the following call to:
// p.move([street: 'Saselbeck', city: 'Hamburg'], '23456789')
p.moveToNewPlace(street: 'Saselbeck', '23456789', city: 'Hamburg')


assert 'Lars' == p.name
assert 'Hamburg' == p.address.city
assert 'Saselbeck' == p.address.street
assert '23456789' == p.phoneNumber 

All named arguments are used are converted by Groovy them a map and passed into the method as first parameter. All other parameters are passed in afterwards. The method can now extract the parameter from the map and perform its setup.

package namedarguments

class Address {
    String street, city
}

class Person {
    String name
    Address address
    String phoneNumber

    def moveToNewPlace(inputAsMap, newPhoneNumber) {
        address.street = inputAsMap.street
        address.city   = inputAsMap.city
        phoneNumber = newPhoneNumber

    }
} 

12.6. Convert a list to a map

To convert a list to a map you can use the collectEntries method.

package com.vogella.groovy.maps

def words = ['Ubuntu', 'Android', 'Mac OS X', 'Windows']

// simple conversion
def result = words.collectEntries {
  [(it):0]
}

assert result.size() == 4
assert result.Ubuntu == 0

// now calculate value with a closure, true if word contains "n"
def map = words.collectEntries {
  [(it): it.contains('n')]
}

println map
assert map.Ubuntu && map.Windows && map.Android && !map.'Mac OS X' 

13. Control structures

13.1. Groovy evaluation of conditions - The Groovy truth

Groovy evaluates a condition defined in a control statement differently from Java. A boolean expression is evaluated the same as in Java, but empty collections or null evaluates to false. The number "0" evaluates to true, all other numbers evaluates to true.

package example

map = [:]
assert !map

list = ["Ubuntu", "Android"]
assert list
assert !0
assert 1
assert -1
assert !""
assert "Hello"
def test = null
assert !test 

Note

This evaluation is commonly known in the Groovy worlds as the Groovy truth.

13.2. if statements

The if and switch are supported, the if statement supports the Groovy truth, e.g., you can use for example a list as parameter in if and Groovy will evaluate this Groovy truth value.

13.3. switch statement and the isCase method

The switch statement is very flexible, everything which implements the isCase method can be used as classifier.Groovy provides an implementation of the isCase() method to Class (using isInstance), Object (using (equals), Collections (using contains) and regular expressions (using matches). You can also specify a closure, which is evaluated to a boolean value.

def testingSwitch(input) {
    def result
    switch (input) {
        case 51:
            result = 'Object equals'
            break
        case ~/^Regular.*matching/:
            result = 'Pattern match'
            break
        case 10..50:
            result = 'Range contains'
            break
        case ["Ubuntu", 'Android', 5, 9.12]:
            result = 'List contains'
            break
        case { it instanceof Integer && it < 50 }:
            result = 'Closure boolean'
            break
        case String:
            result = 'Class isInstance'
            break
        default:
            result = 'Default'
            break
    }
    result
}

assert 'Object equals' == testingSwitch(51)
assert 'Pattern match' == testingSwitch("Regular pattern matching")
assert 'Range contains' == testingSwitch(13)
assert 'List contains' == testingSwitch('Ubuntu')
assert 'Closure boolean' == testingSwitch(9)
assert 'Class isInstance' == testingSwitch('This is an instance of String')
assert 'Default' == testingSwitch(200) 

If several conditions fit, the first case statement is selected.

To use your custom class in a switch statement implement the isCase method.

13.4. Safe navigation operator

You can use safe navigation operator to check safety for null via the ?. operator. This will avoid a NullPointerException if you access properties of an object which is null.

// firstName is null, if user is null. No NPE
def firstName = user?.firstName 

13.5. Elvis operator

The ?: (called the Elvis operator) is a short form for the Java ternary operator. You can use this to set a default if an expression resolves to false or null.

// if user exists, return it, otherwise create a new User

// Groovy with the Elvis operator
String test = null
String result2 = test ?: new String()

// Java version
String user = null;
String result1 = user!=null ? user : new String(); 

14. Loops

14.1. For and while loops

Groovy supports the standard Java for, the for-each and the while loop. Groovy does not support the do while loop.

14.2. Using the each method

While for and while loops are supported the Groovy way of iterating throw a list is using the each() method. Groovy provides this method on several objects include lists, maps and ranges.

This method takes as argument a closure, a block of code which can directly get executed. You can either directly define the name of the variable which the value of each iteration should get assigned to or using the implicit available variable "it".

package de.vogella.groovy.loops



public class PrintLoop{

  public static void main(def args){

    def list = ["Lars", "Ben", "Jack"]

    // using a variable assignment

    list.each{firstName->

      println firstName

    }

    // using the it variable

    list.each{println it}

  }

}
 

Groovy provides also the eachWithIndex method which provides two parameters, the first is the element and the second it the index.

14.3. Iterative with numbers

In additional your have the methods upto(), downto(), times() on number variables. Also you can use ranges (this is an additional datatype) to execute certain things from a number to another number. This is demonstrated by the following example.

package de.vogella.groovy.loops

public class LoopTest{
  public static void main(args){
      5.times {println "Times + $it "}
      1.upto(3) {println "Up + $it "}
      4.downto(1) {print "Down + $it "}
      def sum = 0
      1.upto(100) {sum += it}
      print sum
      (1..6).each {print "Range $it"}
  }  
} 

15. Using lambdas and closures in Groovy

15.1. Defining closures

Closures are code fragments or code blocks which can be used without being a method or a class.

A closure in Groovy is defined via the following construct: {list of parameters-> closure body}. The values before the -> sign define the parameters of the closure.

For the case that only one parameter is used you can use the implicit defined it variable. The last statement of a closure is implicitly used to define the return value, if no return statement is defined. The usage of it variable on the automatic return statement is demonstrates in the following example.

// return the input, using the implicit variable it
def returnInput = {it}

assert 'Test' = returnInput('Test')

// return the input without implicit variable
def returnInput2 = {s-> s}

assert 'Test' = returnInput2('Test') 

15.2. Defining default values in a closure

If you define a closure you can also define default values for its parameters.

package closures

def multiply = {int a, int  b = 10 -> a * b}

assert multiply(2) == 20
assert multiply(2,5) == 10 

15.3. Example: Using closures in the each method

The Groovy collections have several methods which accept a closure as parameter, for example the each method.

List<Integer> list = [5,6,7,8]
list.each({line -> println line})
list.each({println it})


// calculate the sum of the number up to 10

def total = 0
(1..10).each {total+=it} 

15.4. Example: Sort a list by lenght of the string

The Groovy collections have several methods which accept a closure as parameter, for example the each method.

package list

def List strings = "this is a long sentence".split();
strings.sort({s1, s2 -> s1.size() <=> s2.size()});
println strings 

15.5. Using the with method

Every Groovy object has a with method which allows to group method and property calls to an object. The with method gets a closure as parameter and every method call or property access in this closure is applied to the object.

package withmethod

class WithTestClass {
  String property1
  String property2
  List<String> list = []
  def addElement(value) {
    list << value
  }
  def returnProperties () {
    "Property 1: $property1, Property 2: $property2 "
  }
}

def sample = new WithTestClass()
def result= sample.with {
  property1 = 'Input 1'
  property2 = 'This is cool'
  addElement 'Ubuntu'
  addElement 'Android'
  addElement 'Linux'
  returnProperties()
}
println result
assert 3 == sample.list.size()
assert 'Input 1' == sample.property1
assert 'This is cool' == sample.property2
assert 'Linux' == sample.list[2]


def sb = new StringBuilder()
sb.with {
  append 'Just another way to add '
  append 'strings to the StringBuilder '
  append 'object.'
} 

16. Groovy and concurrency

GPars adds support for parallel processing to Groovy. It supports Actors, Map/Reduce, Dataflow, Fork/Join. You find more information on the GPars website.

17. File and network I/O with Groovy

17.1. Groovy and processing files

Groovy adds several convenient methods the File class from Java. The following example demonstrates how to print out every line to the console and and also how to change the output of a line by adding a prefix.

// write the content of the file to the console
File file = new File("./input/test.txt")
file.eachLine{ line -> println line }

// adds a line number in front of each line to the console
def lineNumber = 0
file = new File("./input/test.txt")
file.eachLine{ line ->
  lineNumber++
  println "$lineNumber: $line"
}

// read the file into a String
String s = new File("./input/test.txt").text
println s 

The File object provides methods like eachFile, eachDir and earchFileRecursively which takes an closure as argument.

17.2. Writing to files

Groovy also provides API to write to a file and append to it.

// write the content of the file to the console
File file = new File("output.txt")
file.write "Hello\n"
file.append "Testing\n"
file << "More appending...\n"
File result = new File("output.txt")
println (result.text)
// clean-up
file.delete() 

17.3. Groovy and processing HTTP get requests

Reading an HTTP page is similar to reading a text file.

def data = new URL(http://www.vogella.com).text

// alternatively use Groovy JDK methods
'http://www.vogella.com'.toURL().text 

18. Using template engines in Groovy

A template is some text with predefined places for modificatoins. This template can contain variable reference and Groovy code. The templates engines from Groovy provide createTemplate methods for Strings, Files, Readers or URL and create a Template object based on their input.

Template objects are used to create the final text. A map of key values is passed to the make method of the template which return a Writable.

package template

import groovy.text.SimpleTemplateEngine


 String templateText = '''Project report:

We have currently ${tasks.size} number of items with a total duration of $duration.
<% tasks.each { %>- $it.summary
<% } %>

'''

def list = [
  new Task(summary:"Learn Groovy", duration:4),
  new Task(summary:"Learn Grails", duration:12)]
def totalDuration = 0
list.each {totalDuration += it.duration}
def engine = new SimpleTemplateEngine()
def template = engine.createTemplate(templateText)
def binding = [
duration: "$totalDuration",
tasks: list]

println template.make(binding).toString() 

19. Groovy builders

Groovy supports the builder pattern to create tree-like data structures. The base class for the builder support is BuilderSupport and its subclasses are NodeBuilder, MarkupBuilder, AntBuilder and SwingBuilder.

20. Groovy and Markup like XML or HTML

20.1. Parsing XML with XmlSlurper

Groovy allows to process XML very easily. Groovy provide the XmlSlurper class for this purpose. There are other options but the XmlSlurper is usually considered to be the more efficient in terms of speed and flexibility. XmlSlurper can also be used to transform the XML white parsing it.

XmlSlurper allows to parse an XML document and returns an GPathResult object. You can use GPath expressions to access nodes in the XML tree.

XMLParser allows to parse an XML document and returns an groovy.util.Node object. You can use GPath expressions to access nodes in the XML tree. Dots traverse from parent elements to children, and @ signs represent attribute values.

package mypackage

public class XmlSluperTest{
    static void main(args){
        def xmldocument = '''
        <persons>
            <person age="3"> 
        <name> 
          <firstname>Jim</firstname>  
          <lastname>Knopf </lastname></name>
            </person>
            <person age="4"> 
        <name> 
          <firstname>Ernie</firstname>  
          <lastname>Bernd</lastname></name>
            </person>
        </persons>
        '''

        // in case you want to read a file
        // def persons = new XmlSlurper().parse(new File('data/plan.xml'))
        def persons = new XmlSlurper().parseText(xmldocument)
        def allRecords = persons.person.size()

        // create some output
        println("Number of persons in the XML documents is: $allRecords")
        def person = persons.person[0]
        println("Name of the person tag is: ${person.name}")

        // Lets print out all important information
        for (p in persons.person){
            println "${p.name.firstname.text()}  ${p.name.lastname.text()} is ${p.@age} old"
        }
    }

} 

20.2. Using the MarkupTemplateEngine to generated Markup

Introduce in Groovy 2.3 the MarkupTemplateEngine which supports generating XML-like markup (XML, XHTML, HTML5, etc), but it can be used to generate any text based content.

It is compiled statically to be very fast and supports internationalization. It also supports templates as input.

package mypackage

import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration

String xml_template = '''xmlDeclaration()
tasks {
  tasks.each {
    task (summary: it.summary, duration: it.duration)
  }
}'''
String html_template ='''
yieldUnescaped '<!DOCTYPE html>'
html(lang:'en') {
  head {
    meta('http-equiv':'"Content-Type" content="text/html; charset=utf-8"')
    title('My page')
  }
  body {
    p('This is an example of HTML contents')
  }
}'''

values = [tasks:[
  new Task(summary:"Doit1", duration:4),
  new Task(summary:"Doit2", duration:12)
  ]]
TemplateConfiguration config = new TemplateConfiguration()
def engine = new MarkupTemplateEngine(config)
def template1 = engine.createTemplate(xml_template)
def template2 = engine.createTemplate(html_template)
println template1.make(values)
println template2.make(values) 

Templates support includes.

20.3. Creating Markup (XML) files with the MarkupBuilder

The usage of the MarkupBuilder as "old" builder is demonstrated by the following snippet.

package com.vogella.groovy.builder.markup

import groovy.xml.MarkupBuilder

class TestMarkupWriter {
  static main (args) {
    def date = new Date()
    StringWriter writer = new StringWriter()
    MarkupBuilder builder = new MarkupBuilder(writer)
    builder.tasks {
      for (i in 1..10) {
        task {
          summary (value: "Test $i")
          description (value: "Description $i")
          dueDate(value: "${date.format('MM/dd/yy')}")
        }
      }
    }
    print writer.toString()
  }
} 

The builder in Groovy uses the method names to construct the node and node names. These methods are not defined on the MarkupBuilder class but constructed at runtime.

It is possible to use maps MarkupBuilderin the builder

package com.vogella.groovy.builder.markup

import groovy.xml.MarkupBuilder



class TestMarkupWriterMap {
  static main (args) {
    Map map = [Jim:"Knopf", Thomas:"Edison"]
    def date = new Date()
    StringWriter writer = new StringWriter()
    MarkupBuilder builder = new MarkupBuilder(writer)
    builder.tasks {
      map.each { key, myvalue ->
        person {
        firstname (value : "$key")
        lastname(value : "$myvalue")
        }
      }
    }
    print writer.toString()
  }
} 

You can also use the builder to create valid HTML.

package com.vogella.groovy.builder.markup

import groovy.xml.MarkupBuilder



class TestMarkupHtml {
  static main (args) {
    Map map = [Jim:"Knopf", Thomas:"Edison"]
    def date = new Date()
    StringWriter writer = new StringWriter()
    MarkupBuilder builder = new MarkupBuilder(writer)
    builder.html {
      head { title "vogella.com" }
      body {
        dev (class:"strike") {
          p "This is a line"
        }
      }
      print writer.toString()
    }
  }
} 

21. Groovy and JSON

Similar to the XmlSlurper class for parsing XML, Groovy provides the JsonSlurper for parsing JSON.

import groovy.json.JsonOutput
import groovy.json.JsonSlurper

def a = new JsonSlurper().parse(new File("./input/tasks.json"))
JsonOutput.prettyPrint(a.toString()) 

You can use the setType(LAX) method to parse partially invalid JSON files. With this mode the JSON file can contain // comments, Strings can use '' for quotes can be forgotten.

22. Compile-time meta programming and AST transformations

22.1. What are AST transformations?

An Abstract Syntax Tree (AST) is a in memory representation of code as data. An ADT transformation allows to modify this representation during compile time. This is sometimes called compile-time metaprogramming.

Groovy provides several AST transformations which allows you to reduce the amount of code you have to write.

22.2. @TupleConstructor

If a class is annotated with @TupleConstructor Groovy generates a constructor using all fields.

22.3. @EqualsAndHashCode

The @EqualsAndHashCode annotation can be applied to a class, creates the equals and hashCode method. Includes fields can be customized.

package asttransformations

import groovy.transform.EqualsAndHashCode


@EqualsAndHashCode (excludes=["summary","description"])
public class Task {
  private final long id;
  private String summary;
  private String description;
} 

22.4. @ToString for beans

The @ToString annotation can be applied to a class, generates a toString method, support boolean flags, like includePackage, includeNames, allows to exclude a list of fields.

This annotation typically only considers properties (non-private fields) but you can include them via @ToString(includeFields=true). Via @ToString(excludes=list) we can exclude a list of fields and properties.

package asttransformations

import groovy.transform.ToString


@ToString(includeFields=true)
public class Task {
  private final long id;
  private String summary;
  private String description;
} 

22.5. @Canonical

Combines @ToString, @EqualsAndHashCode and @TupleConstructor.

22.6. @Immutable for immutable Java beans

This annotation marks all fields in a class as final and ensure that there are no setters generate for the fields. It also creates a constructor for all fields, marks the class as final.

22.7. @Delegate

@Delegate can be used on a field. All methods on the delegate are also available on the class with defines the delegate. If several delegates define the same method, it is recommended to override the method. If you do not override Groovy will use the first method it finds.

22.8. @Sortable for beans

You can automatically created a Comparator for a Groovy bean by annotating it with @Sortable. Fields are used in the order of declaration.

You can also include/exclude fields.

package asttransformations

import groovy.transform.Sortable

@Sortable(excludes = ['duration'])
class Task {
  String summary
  String description
  int duration
} 

22.9. @Memoize for methods

If the @Memoize annotation is to a method the Groovy runtime caches the result for invocations with the same parameters. If the annotated method is called the first time with a certain set of parameter, it is executed and the result is cached. If the method is called again with the same parameters, the result is returned from the cache.

package asttransformations

import groovy.transform.Memoized

class MemoizedExample {
  @Memoized
  int complexCalculation (int input){
    println "called"
    // image something really time consuming here
    return input + 1;
  }
} 

package asttransformations

def m = new MemoizedExample()

// prints "called"
m.complexCalculation(1)

// no output as value is returned from cache
m.complexCalculation(1) 

22.10. @AnnotationCollector for combining AST Transformations annotations

The AnnotationCollector allows to combine other AST Transformations annotations.

package asttransformations;

import groovy.transform.AnnotationCollector
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString

@ToString(includeNames=true)
@EqualsAndHashCode
@AnnotationCollector
public @interface Pojo {} 

You can use this annotation, it is also possible to override parameters in them.

package asttransformations


@Pojo
class Person {
  String firstName
  String lastName
}

@Pojo(includeNames=false)
class Person2 {
  String firstName
  String lastName
} 

package asttransformations


def p = new Person(firstName:"Lars" ,lastName:"Vogel")
println p
// output: asttransformations.Person(firstName:Lars, lastName:Vogel)

p = new Person2(firstName:"Lars" ,lastName:"Vogel")
println p
// output: asttransformations.Person2(Lars, Vogel) 

22.11. @Bindable observable Properties

The Java beans specification requires that Java beans support PropertyChangeSupport for all fields.

The @groovy.beans.Bindable annotation can be applied to a whole class or a method. If the property is applied to a class, all methods will be treated as having the @Bindable annotation. This will trigger Groovy to generated a java.beans.PropertyChangeSupport property in the class and generate methods so that listeners can register and deregister. Also all setter methods will notfiy the property change listener.

The following listing shows the Java version of a Java Bean with one property.

22.12. @Builder

The @Builder can be applied to a class and generates transparently a builder for this class.

package asttransformations

import groovy.transform.ToString
import groovy.transform.builder.Builder

@Builder
@ToString(includeNames=true)
class TaskWithBuilder {
  String summary
  String description
  int duration
} 

package asttransformations

TaskWithBuilder test = TaskWithBuilder.builder().
            summary("Help").
            description("testing").
            duration(5).
            build();

print test; 

22.13. @Grab for dependency management

Groovy allows to add Maven dependencies to your Groovy script or Groovy class using the @Grab annotation. Before a Groovy program is executed it reads the @Grab annotation, resolves the Maven dependencies, downloads them and adds them to the classpath of the program.

@Grab(group='org.eclipse.jetty.aggregate', module='jetty-all', version='7.6.15.v20140411') 

Using the @GrabResolver annotation you can specify the Maven repository you want to use. For example @GrabResolver(name='myrepo', root='http://myrepo.my-company.com/') .

22.14. Other AST Transformations

The following table lists other commonly used annotations in Groovy code:

Table 4. AST transformation annotations

AnnotationDescription
@SingletonMakes annotated class a Singleton, access via ClassName.instance.
@PackageScopeDefines fields, methods or class as package scope, which is the default access modifier in Java.


22.15. Writing custom transformations

You can also define you custom local or global transformations. For a local transformation you would write your own annotation and write a processors for that and use the annotation on an element in your Groovy class. The Groovy compiler calls your processors to transform the input into something else.

Global transformations are applied to every single source unit in the compilation without the need for additional customization.

23. Meta Object Protocol

23.1. What is the Meta Object Protocol_

The Meta-Object Protocol (MOP) is the underlying layer in Groovy which allows you to add methods and properties to an object at runtime. Using MOP you can methods and properties at runtime to existing objects.

23.2. Calling methods or accessing properties on a Groovy object

If a method is called or a property is accessed in a class and this class does not define this method / property then pre-defined methods are called which can be used to handle this call.

  • def methodMissing (String name, args) - Called for missing method

  • void setProperty (String property, Object o) - called for non existing setter of a property

  • Object getProperty (String property) - called for non existing getter of a property

Instances of Groovy object have default implementations of these methods, but an Groovy object can override these methods. The Groovy framework calls the methods at runtime if a method or property cannot be found. This approach is for example used by the Groovy builder pattern, it pretends to have certain method.

23.3. Adding methods and properties

Using the .metaclass access you can add properties and methods to an existing class.

Class Todo {}

Todo.metaClass.summary = 'Learn MOP'
Todo.metaClass.done = false
Todo.metaClass.markAsFinish = {-> done=true}

Todo t = new Todo()
t.markAsFinish() 

24. Exercise: Meta Object Protocol

24.1. Target of this exercise

In this exercise you learn how to extend a Groovy class using the Meta Object Protocol.

24.2. Making a Groovy object responding to all methods and property calls

Create the following Groovy class. This class returns a fixed value for every property asked and it fakes method calls.

package mop


public class AnyMethodExecutor{
  // Should get ignored
  String value ="Lars"

  // always return 5 no matter which property is called
  Object getProperty (String property){
    return 5;
  }

  void setProperty (String property, Object o){
    // ignore setting
  }

  def methodMissing (String name, args){
    def s = name.toLowerCase();
    if (!s.contains("hello")) {
      return "This method is just fake"
    } else {
      return "Still a fake method but 'hello' back to you."

    }
  }

} 

Test this method via the following Groovy script.

package mop

def test = new AnyMethodExecutor ();

// you can call any method you like
// on this class
assert "This method is just fake" == test.hall();
assert "This method is just fake" == test.Hallo();
assert "Still a fake method but 'hello' back to you." == test.helloMethod();

// setting is basically ignored
test.test= 5;
test.superDuperCool= 100

// all properties return 5
assert test.superDuperCool == 5
assert test.value == 5; 

24.3. Exercise: Adding JSON output to Groovy class, the ugly and the smart way

Create the following Groovy class.

package mop;

import groovy.json.JsonBuilder
import groovy.json.JsonOutput

public class Task {
  String summary
  String description

  def methodMissing (String name, args){
    if (name=="toJson") {
      JsonBuilder b1 = new JsonBuilder(this)
      return JsonOutput.prettyPrint(b1.toString())
    }
  }
} 

Is uses the methodMissing to respond to a toJson method call. This implementation is a bit ugly as it "pollutes" our domain model with "framework" code.

This script trigger the JSON generation.

package mop

def t = new Task(summary: "Mop",description:"Learn all about Mop");
println t.toJson() 

Groovy allows to created an instance of MetaClass and register it automatic for a certain class. This registration is based on a package naming conversion:

// define an instance of Metaclass in such a package
// Groovy will register it a MetaClass
groovy.runtime.metaclass.[thePackage].[theClassName]MetaClass 

Create the following class in the listed package to register it as MetaClass for your class.

package groovy.runtime.metaclass.mop;

import groovy.json.JsonBuilder
import groovy.json.JsonOutput

class TaskMetaClass extends DelegatingMetaClass {

  TaskMetaClass(MetaClass meta) {
    super(meta)
  }

  @Override
  def invokeMethod(Object object, String method, Object[] args) {
    println method
    if (method == "toJson") {
      JsonBuilder b1 = new JsonBuilder(object)
      return JsonOutput.prettyPrint(b1.toString())
    }
    super.invokeMethod(object, method, args)
  }
} 

This allows you to clean up your domain model.

package mop;

import groovy.json.JsonBuilder
import groovy.json.JsonOutput

public class Task {
  String summary
  String description
} 

Run your small test script again and validate that the conversion to JSON still works.

package mop

def t = new Task(summary: "Mop",description:"Learn all about Mop");
println t.toJson() 

24.4. Exercise: Adding a method to String

The following example demonstrates how you can add a method to the String class using closures.

package com.vogella.groovy.mop.examples

def reverseStringAndAddLars(String s){
  (s.reverse()<<"Lars").toString()
}

String.metaClass.reverseStringAndAddLars = { -> reverseStringAndAddLars(delegate) }

println 'Hamburg'.reverseStringAndAddLars()
println 'grubmaHLars'

def test = 'Hamburg'.reverseStringAndAddLars()

assert test == "grubmaHLars" 

25. Using Groovy classes in Java

25.1. Calling Groovy classes directly

To use Groovy classes in Java classes you need to add the Groovy runtime to the Java classpath.

Create a new Java project "de.vogella.groovy.java". Create package "de.vogella.groovy.java"

Create the following Groovy class.

package de.vogella.groovy.java


public class Person{
  String firstName
  String lastName
  int age
  def address
} 

Create the following Java class.

package de.vogella.groovy.java;

public class Main {
  public static void main(String[] args) {
    Person p = new Person();
    p.setFirstName("Lars");
    p.setLastName("Vogel");
    System.out.println(p.getFirstName() + " " + p.getLastName());
  }
} 

You should be able to run this Java program.

Right-click your project, select "Properties" and check that the build path includes the Groovy libraries.

25.2. Calling a script

import java.io.FileNotFoundException;
import java.io.FileReader;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ExecuteGroovyViaJSR223 {
  public static void main(String[] args) {
    ScriptEngine engine = new ScriptEngineManager()
        .getEngineByName("groovy");
    try {
      engine.put("street", "Haindaalwisch 17a");
      engine.eval("println 'Hello, Groovy!'");
      engine.eval(new FileReader("src/hello.groovy"));
    } catch (ScriptException e) {
      e.printStackTrace();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
  }
} 

println "hello"
// if not defined it becomes part of the binding
println street 

26. Using Groovy in a Maven or Gradle build

26.1. Using Groovy in a Maven build

Maven is a well established build tool in the Java world. Integrating Gradle in the build is trivial. You basically only have to add one dependency to your pom file. To use Groovy code in your plug-in simply add the following dependency to your pom.xml file.

<dependencies>
    ... other dependencies
  <dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.4.5</version>
  </dependency>
</dependencies> 

26.2. Using Groovy in a Gradle build

To use Groovy code in your Gradle build, simply add the following dependency to your pom.xml file.

apply plugin: 'groovy'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.4.5'
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值