概述

Groovy是一种基于JVM的面向对象语言,如果不声明public/private等访问权限的话,Groovy中类及其变量默认都是public的。

Groovy中有以下特点:

  • 同时支持静态和动态类型

  • 支持运算符重载

  • 对正则表达式的本地支持

  • 可以使用现有的Java库及Java语法

  • 不需要分号

  • 可省略return关键字,默认用最后一个表达式为返回

  • 使用命名的参数初始化beans和默认的构造器:new Server(name: "Obelix", cluster: aCluster)

  • Groovy里的is()方法等同于Java里的==,Groovy中的==是更智能的equals()

  • 在同一个bean中使用with()来重复某一个操作:

    // Java
    server.name = application.name
    server.status = status
    server.sessionCount = 3
    server.start()
    server.stop()
    
    // Groovy
    server.with {
        name = application.name
        status = status
        sessionCount = 3
        start()
        stop()
    }

基本语法

class Test {
    static void main(String[] args) {
        println('Hello World.')
    }
}

在Groovy中下列包是默认导入的:

import java.lang.* 
import java.util.* 
import java.io.* 
import java.net.* 

import groovy.lang.* 
import groovy.util.* 

import java.math.BigInteger 
import java.math.BigDecimal

Groovy中使用def来定义变量。

数据类型

内置数据类型

  • byte -这是用来表示字节值。例如2。
  • short -这是用来表示一个短整型。例如10。
  • int -这是用来表示整数。例如1234。
  • long -这是用来表示一个长整型。例如10000090。
  • float -这是用来表示32位浮点数。例如12.34。
  • double -这是用来表示64位浮点数,这些数字是有时可能需要的更长的十进制数表示。例如12.3456565。
  • char -这定义了单个字符文字。例如“A”。
  • Boolean -这表示一个布尔值,可以是true或false。
  • String -这些是以字符串的形式表示的文本。

Groovy提供了多种表示String字面量的方法。 Groovy中的字符串可以用单引号(’),双引号(“)或三引号(”“”)括起来。此外,由三重引号括起来的Groovy字符串可以跨越多行。

Groovy中的字符串是字符的有序序列,字符串索引从零开始,还允许负索引从字符串的末尾开始计数。

class Example { 
    static void main(String[] args) { 
        String sample = "Hello world"; 
        println(sample[4]); // Print the 5 character in the string
            
        //Print the 1st character in the string starting from the back 
        println(sample[-1]); 
        println(sample[1..2]);//Prints a string starting from Index 1 to 2 
        println(sample[4..2]);//Prints a string starting from Index 4 back to 2 
    }
}

对象类型(包装器类型)

  • java.lang.Byte
  • java.lang.Short
  • java.lang.Integer
  • java.lang.Long
  • java.lang.Float
  • java.lang.Double
  • 父类为Number

Groovy中的变量可以通过两种方式定义: 使用数据类型的语法,或者使用def关键字。对于变量定义,必须明确提供类型名称或在替换中使用“def”。

class Example { 
   static void main(String[] args) { 
      //Example of a int datatype 
      int x = 5; 

      //Example of a long datatype 
      long y = 100L; 

      //Example of a floating point datatype 
      float a = 10.56f; 

      //Example of a double datatype 
      double b = 10.5e40; 

      //Example of a BigInteger datatype 
      BigInteger bi = 30g; 

      //Example of a BigDecimal datatype 
      BigDecimal bd = 3.5g; 

      println(x); 
      println(y); 
      println(a); 
      println(b); 
      println(bi); 
      println(bd); 
   } 
}

运算符

Groovy语言支持正常的算术运算符任何语言。

范围运算符:

def range = 5..10;
println(range.get(3))

范围由序列中的第一个和最后一个值表示,Range可以是包含或排除。包含范围包括从第一个到最后一个的所有值,而独占范围包括除最后一个之外的所有值。

  • 1..10 - 包含范围的示例
  • 1..<10 - 独占范围的示例
  • ‘a’..’x’ - 范围也可以由字符组成
  • 10..1 - 范围也可以按降序排列
  • ‘x’..’a’ - 范围也可以由字符组成并按降序排列。

可通过list[index]方式访问。

方法 用法
contains() 检查范围是否包含特定值
get() 返回此范围中指定位置处的元素。
getFrom() 获得此范围的下限值。
getTo() 获得此范围的上限值。
isReverse() 这是一个反向的范围,反向迭代
size() 返回此范围的元素数。
subList() 返回此指定的fromIndex(包括)和toIndex(排除)之间的此范围部分的视图

循环

语句 描述
while 首先通过计算条件表达式(布尔值)来执行,如果结果为真,则执行while循环中的语句。
for 用于遍历一组值。
for-in 用于遍历一组值。
break 用于改变循环和switch语句内的控制流。
continue 补充了break语句。它的使用仅限于while和for循环。

方法

Groovy中的方法是使用返回类型或使用def关键字定义的。方法可以接收任意数量的参数。定义参数时,不必显式定义类型,可以给参数使用初始值。可以添加修饰符,如public,private和protected。默认情况下,如果未提供可见性修饰符,则该方法为public。

最简单的方法是没有参数的方法,如下所示:

class Example {
    static def DisplayName() {
        println("This is how methods work in groovy");
        println("This is an example of a simple method");
    } 

    static void main(String[] args) {
        DisplayName();
    } 
}

以下是使用参数的简单方法的示例

class Example {
    static void sum(int a,int b) {
        int c = a+b;
        println(c);
    }
    // 或
    static void sum(a, b) {
        int c = a + b;
        println(c);
    }

    static void main(String[] args) {
        sum(10,5);
    }
}

Groovy中还有一个规定来指定方法中的参数的默认值。 如果没有值传递给参数的方法,则使用缺省值。 如果使用非默认和默认参数,则必须注意,默认参数应在参数列表的末尾定义。

以下是使用参数的简单方法的示例:

class Example { 
   static void sum(int a, int b = 5) { 
      int c = a + b; 
      println(c); 
   } 
	
   static void main(String[] args) {
      sum(6); 
   } 
}

I/O

Groovy在使用I/O时提供了许多辅助方法,同时也可以使用Java原生IO类。

读取文件

以下示例将输出Groovy中的文本文件的所有行。方法eachLine内置在Groovy中的File类中,目的是确保文本文件的每一行都被读取。

import java.io.File

class Example { 
   static void main(String[] args) { 
      new File("E:/Example.txt").eachLine {  
         line -> println "line : $line"; 
      } 
   } 
}

如果要将文件的整个内容作为字符串获取,可以使用文件类的text属性,即:String s = file.text

写入文件

如果想写入文件,则需要使用Write类输出文本到一个文件中:

import java.io.File 
class Example { 
   static void main(String[] args) { 
      new File('E:/','Example.txt').withWriter('utf-8') { 
         writer -> writer.writeLine 'Hello World' 
      }  
    }
}

获取文件的大小

如果要获取文件的大小,可以使用文件类的length属性来获取:

class Example {
   static void main(String[] args) {
      File file = new File("E:/Example.txt")
      println "The file ${file.absolutePath} has ${file.length()} bytes"
   } 
}

文件是否是目录

如果要查看路径是文件还是目录,可以使用File类的isFile和isDirectory选项:

class Example { 
   static void main(String[] args) { 
      def file = new File('E:/') 
      println "File? ${file.isFile()}" 
      println "Directory? ${file.isDirectory()}" 
   } 
}

创建目录

如果要创建一个新目录,可以使用File类的mkdir函数:

class Example {
   static void main(String[] args) {
      def file = new File('E:/Directory')
      file.mkdir()
   } 
}

删除文件

如果要删除文件,可以使用File类的delete功能:

class Example {
   static void main(String[] args) {
      def file = new File('E:/Example.txt')
      file.delete()
   } 
}

复制文件

Groovy还提供将内容从一个文件复制到另一个文件的功能:

class Example {
   static void main(String[] args) {
      def src = new File("E:/Example.txt")
      def dst = new File("E:/Example1.txt")
      dst << src.text
   }
}

获取目录内容

Groovy还提供了列出驱动器中的驱动器和文件的功能,以下示例显示如何使用File类的listRoots函数显示机器上的驱动器:

class Example { 
   static void main(String[] args) { 
      def rootFiles = new File("test").listRoots() 
      rootFiles.each { 
         file -> println file.absolutePath 
      }
   }
}

以下示例显示如何使用File类的eachFile函数列出特定目录中的文件:

class Example {
   static void main(String[] args) {
      new File("E:/Temp").eachFile() {  
         file->println file.getAbsolutePath()
      }
   } 
}

如果要递归显示目录及其子目录中的所有文件,则可以使用File类的eachFileRecurse函数:

class Example { 
   static void main(String[] args) {
      new File("E:/temp").eachFileRecurse() {
         file -> println file.getAbsolutePath()
      }
   }
}

List

  • [11,12,13,14] - 整数值列表
  • [‘Angular’,’Groovy’,’Java’] - 字符串列表
  • [1,2,[3,4],5] - 嵌套列表
  • [‘Groovy’,21,2.11] - 异构的对象引用列表
  • [] - 空列表

可通过list[index]方式访问。

方法 用法
add() 将新值附加到此列表的末尾。
contains() 如果此列表包含指定的值,则返回true。
get() 返回此列表中指定位置的元素。
isEmpty() 如果此列表不包含元素,则返回true
minus() 创建一个由原始元素组成的新列表,而不是集合中指定的元素。
plus() 创建由原始元素和集合中指定的元素组成的新列表。
pop() 从此列表中删除最后一个项目
remove() 删除此列表中指定位置的元素。
reverse() 创建与原始列表的元素相反的新列表
size() 获取此列表中的元素数。
sort() 返回原始列表的排序副本。

多重赋值和多返回值:

// def(var1, var2, var3) = [value1, value2, value3]
def (a, b, c) = fun()

def fun() {
    // ...
    return [f1, f2, f3]
}

Map

  • [‘TopicName’: ‘Lists’, ‘TopicName’: ‘Maps’] - 具有TopicName作为键的键值对的集合及其相应的值。
  • [:] - 空映射。
方法 用法
containsKey() 此映射是否包含此键
get() 查找此Map中的键并返回相应的值。如果此映射中没有键的条目,则返回null。
keySet() 获取此映射中的一组键。
put() 将指定的值与此映射中的指定键相关联。如果此映射先前包含此键的映射,则旧值将替换为指定的值。
size() 返回此地图中的键值映射的数量。
values() 返回此地图中包含的值的集合视图。

键可以是任意类型:

def m = [1: 2, 2: 3]
println(m.get(2))

Date

class Example { 
   static void main(String[] args) { 
      Date date = new Date(); 
      // 分配一个Date对象并初始化它,以便它表示分配的时间,以最近的毫秒为单位。
      System.out.println(date.toString()); 
   } 
}
-> output:
Thu Dec 10 21:31:15 GST 2015

class Example {
   static void main(String[] args) {
      Date date = new Date(100);
      // 分配一个Date对象并将其初始化以表示自标准基准时间(称为“该历元”,即1970年1月1日,00:00:00 GMT)起指定的毫秒数。
      System.out.println(date.toString());
   } 
}
->output:
Thu Jan 01 04:00:00 GST 1970

下面是一些常用方法:

方法 作用
after() 测试此日期是否在指定日期之后。
equals() 比较两个日期的相等性。当且仅当参数不为null时,结果为true,并且是表示与该对象时间相同的时间点(毫秒)的Date对象。
compareTo() 比较两个日期的顺序。
toString() 将此Date对象转换为字符串
before() 测试此日期是否在指定日期之前。
getTime() 返回自此Date对象表示的1970年1月1日,00:00:00 GMT以来的毫秒数。
setTime() 设置此Date对象以表示一个时间点,即1970年1月1日00:00:00 GMT之后的时间毫秒。

regex

Groovy使用〜“regex”表达式本地支持正则表达式,引号中包含的文本表示用于比较的表达式:

def regex = ~'Groovy'
字符 说明
\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,”n”匹配字符”n”。”\n”匹配换行符。序列”\\“匹配”\“,”(“匹配”(“。
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与”\n”或”\r”之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与”\n”或”\r”之前的位置匹配。
* 零次或多次匹配前面的字符或子表达式。例如,zo 匹配”z”和”zoo”。 等效于 {0,}。
+ 一次或多次匹配前面的字符或子表达式。例如,”zo+”与”zo”和”zoo”匹配,但与”z”不匹配。+ 等效于 {1,}。
? 零次或一次匹配前面的字符或子表达式。例如,”do(es)?”匹配”do”或”does”中的”do”。? 等效于 {0,1}。
{n} n 是非负整数。正好匹配 n 次。例如,”o{2}”与”Bob”中的”o”不匹配,但与”food”中的两个”o”匹配。
{n,} n 是非负整数。至少匹配 n 次。例如,”o{2,}”不匹配”Bob”中的”o”,而匹配”foooood”中的所有 o。”o{1,}”等效于”o+”。”o{0,}”等效于”o*”。
{n,m} M 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,”o{1,3}”匹配”fooooood”中的头三个 o。’o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间。
? 当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是”非贪心的”。”非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的”贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串”oooo”中,”o+?”只匹配单个”o”,而”o+”匹配所有”o”。
. 匹配除”\r\n”之外的任何单个字符。若要匹配包括”\r\n”在内的任意字符,请使用诸如”[\s\S]”之类的模式。
x\ y 匹配 x 或 y。例如,’z
[xyz] 字符集。匹配包含的任一字符。例如,”[abc]”匹配”plain”中的”a”。
xyz 反向字符集。匹配未包含的任何字符。例如,”abc”匹配”plain”中”p”,”l”, “i”,”n”。
[a-z] 字符范围。匹配指定范围内的任何字符。例如,”[a-z]”匹配”a”到”z”范围内的任意小写字母。
a-z 反向范围字符。匹配不在指定的范围内的任何字符。例如,”a-z”匹配任何不在”a”到”z”范围内的任何字符。
\b 匹配一个字边界,即字与空格间的位置。例如,”er\b”匹配”never”中的”er”,不匹配”verb”中的”er”。
\B 非字边界匹配。”er\B”匹配”verb”中的”er”,但不匹配”never”中的”er”。
\cx 匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在A-Z 或 a-z 之间。如果不是这样,则假定 c 就是”c”字符本身。
\d 数字字符匹配。等效于 [0-9]。
\D 非数字字符匹配。等效于 0-9
\f 换页符匹配。等效于 \x0c 和 \cL。
\n 换行符匹配。等效于 \x0a 和 \cJ。
\r 匹配一个回车符。等效于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\S 匹配任何非空白字符。与 \f\n\r\t\v 等效。
\t 制表符匹配。与 \x09 和 \cI 等效。
\v 垂直制表符匹配。与 \x0b 和 \cK 等效。
\w 匹配任何字类字符,包括下划线。与”[A-Za-z0-9_]”等效。
\W 与任何非单词字符匹配。与”A-Za-z0-9_”等效。

面向对象

Groovy中的面向对象与Java很类似。

特征

特征是语言的结构构造,允许:

  • 行为的组成。
  • 接口的运行时实现。
  • 与静态类型检查/编译的兼容性

它们可以被看作是承载默认实现和状态的接口,使用trait关键字定义trait。

class Test {
    static void main(String[] args) {
        Student s = new Student()
        s.id = 20
        s.age = 10
        println(s.id)
        println(s.age)
        s.total()
        s.test1()
        s.test2()
        s.test3()
    }
}

interface Total {
    void total()
}

trait Marks implements Total {
    void test1() {
        println('Marks')
    }

    void total() {
        println('total')
    }
}

trait Marks1 extends Marks {
    int age;

    void test2() {
        println('Marks1 = ' + age)
    }
}

trait Marks2 {
    void test3() {
        println('Marks2')
    }
}

class Student implements Marks1, Marks2 {
    int id
}

闭包

概述

闭包是一个短的匿名代码块。它通常跨越几行代码。一个方法甚至可以将代码块作为参数。它们是匿名的。

static void main(String[] args) {
    def clos = {println "Hello World"};
    clos.call();
    clos();
}

在Groovy中,每个闭包都是groovy.lang.Closure的实例,执行闭包对象有两种,一是直接用括号+参数,二是调用call方法+参数。

闭包的形参

static void main(String[] args) {
    def clos = {param -> println "Hello ${param}"};
    clos.call("World");
}

static void main(String[] args) {
    def clos = {println "Hello ${it}"};
    clos.call("World");
}

闭包和变量

闭包可以在定义闭包时引用变量。

static void main(String[] args) {
    def str1 = "Hello";
    def clos = {param -> println "${str1} ${param}"}
    clos.call("World");

    // We are now changing the value of the String str1 which is referenced in the closure
    str1 = "Welcome";
    clos.call("World");
}
->output:
    Hello World
    Welcome World

在方法中使用闭包

以下示例显示如何将闭包作为参数发送到方法。

class Example {
   def static Display(clo) {
      // This time the $param parameter gets replaced by the string "Inner"
      clo.call("Inner");
   }

   static void main(String[] args) {
      def str1 = "Hello";
      def clos = { param -> println "${str1} ${param}" }
      clos.call("World");

      // We are now changing the value of the String str1 which is referenced in the closure
      str1 = "Welcome";
      clos.call("World");

      // Passing our closure to a method
      Example.Display(clos);
   }
}
->output:
    Hello World
    Welcome World
    Welcome Inner

def filter(array, block) {
    for (val in array) {
        block(val)
    }
}

iarray = [1, 2, 3, 4, 5, 6, 7, 8, 9]
total = []
filter(iarray, { if (it % 2 == 0) total << it })
println total // [2, 4, 6, 8]

total = []
filter(iarray, { if (it > 5) total << it })
println total // [6, 7, 8, 9]

当闭包作为最后一个参数时,可以有其它写法

filter(iarray) { if (it % 2 == 0) total << it }

集合和字符串中的闭包

List,Map和String方法接受一个闭包作为参数。

class Example {
   static void main(String[] args) {
      def lst = [11, 12, 13, 14];
      lst.each {println it}
   }
}

class Example {
   static void main(String[] args) {
      def mp = ["TopicName" : "Maps", "TopicDescription" : "Methods in Maps"]
      mp.each {println it}
      mp.each {println "${it.key} maps to: ${it.value}"}
   }
}

class Example {
   static void main(String[] args) {
      def lst = [1,2,3,4];
      lst.each {println it}
      println("The list will only display those numbers which are divisible by 2")
      lst.each{num -> if(num % 2 == 0) println num}
   }
}

方法

方法 用法
find() find方法查找集合中与某个条件匹配的第一个值。
findAll() 它找到接收对象中与闭合条件匹配的所有值。
any() & every() 方法any迭代集合的每个元素,检查布尔谓词是否对至少一个元素有效。
collect() 该方法通过集合收集迭代,使用闭包作为变换器将每个元素转换为新值。

闭包委托

在闭包内部,有三个内置对象this,owner,delegate,我们可以直接this,owner,delegate调用,或者用get方法:

  • getThisObject() 等于 this
  • getOwner() 等于 owner
  • getDelegate() 等于delegate
  • this 该属性指向定义闭包的类的实例对象
  • owner 该属性和 this 类似,但是闭包中也可以定义闭包的,如果闭包 A 内定义了闭包 B,那么闭包 B 的 owner 指向的是其外部的闭包 A
  • delegate 该值初始化时是和 owner 相同的,但是该值可以通过接口将其它对象赋值给 delegate,来实现方法的委托功能
class Hello {

    static void main(String[] args) {
        def p = new Person(name: "hearing")
        p.clo()
    }
}

class Person {
    String name
    def clo = {
        println(name)
        // 都有.name属性
        println(this)
        println(owner)
        println(delegate)

        def clo1 = {
            println(name)
            println(this)
            // 没有.name属性
            println(owner)
            println(delegate)
        }
        clo1.delegate = Person
        clo1()
    }
}
->output:
hearing
Person@35d176f7
Person@35d176f7
Person@35d176f7
hearing
Person@35d176f7
Person$_closure1@6ebc05a6
class Person

设置delegate的意义就是将闭包和一个具体的对象关联起来,在闭包中可以访问被代理对象的属性和方法,如果闭包所在的类或闭包中和被代理的类中有相同名称的方法,那么有几种代理策略:

  • Closure.OWNER_FIRST是默认策略。优先在owner寻找,owner没有再delegate
  • Closure.DELEGATE_FIRST:优先在delegate寻找,delegate没有再owner
  • Closure.OWNER_ONLY:只在owner中寻找
  • Closure.DELEGATE_ONLY:只在delegate中寻找
  • Closure.TO_SELF:

用法实例:

# Person.groovy
class Person {
    String name
    int age

    void eat(String food) {
        println("你喂的${food}真难吃")
    }
    
    @Override
    String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}'
    }
}

# Main.groovy
class Main {
    void eat(String food){
        println "我根本不会吃,不要喂我${food}"
    }
    def cc = {
        name = "hanmeimei"
        age = 26
        eat("油条")
    }

    static void main(String... args) {
        Main main = new Main()
        Person person = new Person(name: "lilei", age: 14)
        println person.toString()

        main.cc.delegate = person
        // main.cc.setResolveStrategy(Closure.DELEGATE_FIRST)
        main.cc.setResolveStrategy(Closure.OWNER_FIRST)
        main.cc.call()
        println person.toString()
    }
}

DSL(领域定义语言)

class Gradle {
    String type
    String version
    String result

    def type(type) {
        this.type = type
    }

    def version(version) {
        this.version = version
    }

    def result(str) {
        result = version + type
        println str + result
    }

    static def build(closure) {
        Gradle gradle = new Gradle()
        closure.delegate = gradle
        closure.call()
    }
}

Gradle.build {
    type 'compile'
    version '1.11 '
    result 'build: '
}

-> output
// build: 1.11 compile

Groovy XML

概述

Groovy语言提供了对XML语言的丰富支持,其两个最基本的XML类是:

  • XML生成器:groovy.xml.MarkupBuilder
  • XML解析器:groovy.util.XmlParser

MarkupBuilder

import groovy.xml.MarkupBuilder 

class Example {
    static void main(String[] args) {
        def mp = [1 : ['Enemy Behind', 'War, Thriller','DVD','2003', 
            'PG', '10','Talk about a US-Japan war'],
            2 : ['Transformers','Anime, Science Fiction','DVD','1989', 
            'R', '8','A scientific fiction'],
            3 : ['Trigun','Anime, Action','DVD','1986', 
            'PG', '10','Vash the Stam pede'],
            4 : ['Ishtar','Comedy','VHS','1987', 'PG', 
            '2','Viewable boredom ']] 

        def mB = new MarkupBuilder()  

        // Compose the builder
        def MOVIEDB = mB.collection('shelf': 'New Arrivals') {
            mp.each { sd -> 
                mB.movie('title': sd.value[0]) {  
                type(sd.value[1])
                format(sd.value[2])
                year(sd.value[3]) 
                rating(sd.value[4])
                stars(sd.value[4]) 
                description(sd.value[5]) 
                }
            }
        }
    } 
}

运行上面代码会生成如下XML内容:

<collection shelf='New Arrivals'>
    <movie title='Enemy Behind'>
        <type>War, Thriller</type>
        <format>DVD</format>
        <year>2003</year>
        <rating>PG</rating>
        <stars>PG</stars>
        <description>10</description>
    </movie>
    <movie title='Transformers'>
        <type>Anime, Science Fiction</type>
        <format>DVD</format>
        <year>1989</year>
        <rating>R</rating>
        <stars>R</stars>
        <description>8</description>
    </movie>
    <movie title='Trigun'>
        <type>Anime, Action</type>
        <format>DVD</format>
        <year>1986</year>
        <rating>PG</rating>
        <stars>PG</stars>
        <description>10</description>
    </movie>
    <movie title='Ishtar'>
        <type>Comedy</type>
        <format>VHS</format>
        <year>1987</year>
        <rating>PG</rating>
        <stars>PG</stars>
        <description>2</description>
    </movie>
</collection>

XmlParser

对于上面的XML,可以使用下述方法解析:

import groovy.xml.MarkupBuilder 
import groovy.util.*

class Example {

    static void main(String[] args) { 
        
        def parser = new XmlParser()
        def doc = parser.parse("Movies.xml");

        doc.movie.each{ bk->
            print("Movie Name:")
            println "${bk['@title']}"

            print("Movie Type:")
            println "${bk.type[0].text()}"

            print("Movie Format:")
            println "${bk.format[0].text()}"

            print("Movie year:")
            println "${bk.year[0].text()}"

            print("Movie rating:")
            println "${bk.rating[0].text()}"

            print("Movie stars:")
            println "${bk.stars[0].text()}"

            print("Movie description:")
            println "${bk.description[0].text()}"
            println("*******************************")
        }
    }
}

运行上面的程序可以得到以下结果:

Movie Name:Enemy Behind 
Movie Type:War, Thriller 
Movie Format:DVD 
Movie year:2003 
Movie rating:PG 
Movie stars:10 
Movie description:Talk about a US-Japan war 
******************************* 
Movie Name:Transformers 
Movie Type:Anime, Science Fiction 
Movie Format:DVD 
Movie year:1989 
Movie rating:R 
Movie stars:8 
Movie description:A schientific fiction 
******************************* 
Movie Name:Trigun 
Movie Type:Anime, Action
Movie Format:DVD 
Movie year:1986 
Movie rating:PG 
Movie stars:10 
Movie description:Vash the Stam pede! 
******************************* 
Movie Name:Ishtar 
Movie Type:Comedy 
Movie Format:VHS 
Movie year:1987 
Movie rating:PG 
Movie stars:2 
Movie description:Viewable boredom

Groovy JSON

概述

Groovy语言提供了两个类来处理JSON格式的数据:

  • JSON生成器:groovy.json.JsonOutput
  • JSON解析器:groovy.json.JsonSlurper

JsonOutput

  • 用法:Static string JsonOutput.toJson(datatype obj)
  • 参数:可以是数据类型的对象,数字,布尔,字符,字符串,日期,地图,闭包等。
  • 返回类型:一个JSON字符串。
import groovy.json.JsonOutput

class Example {
    static void main(String[] args) {
        def output = JsonOutput.toJson([name: 'John', ID: 1])
        println(output);  
    }
}

以上程序的输出如下:

{"name":"John","ID":1}

JsonOutput也可以用于普通的Groovy对象:

import groovy.json.JsonOutput  
class Example {
    static void main(String[] args) {
        def output = JsonOutput.toJson([ new Student(name: 'John', ID: 1), new Student(name: 'Mark', ID: 2)])
        println(output);
    }
}

class Student {
   String name
   int ID; 
}

以上程序的输出如下:

[{"name":"John","ID":1},{"name":"Mark","ID":2}]

JsonSlurper

JsonSlurper是一个将JSON文本或阅读器内容解析为Groovy数据结构的类,如Map,列表和原始类型,如Integer,Double,Boolean和String等。

  • 用法:def slurper = new JsonSlurper()

JsonSlurper类自带了一些用于解析器实现的变体,例如当读取从Web服务器的响应返回的JSON时使用解析器JsonParserLax变量是有益的,此parser允许在JSON文本中存在注释以及没有引号字符串等。要指定此类型的解析器需要在定义JsonSlurper的对象时使用JsonParserType.LAX解析器类型。

http.request( GET, TEXT ) {
    headers.Accept = 'application/json'
    headers.'User-Agent' = USER_AGENT

    response.success = { 
        res, rd ->  
        def jsonText = rd.text 

        //Setting the parser type to JsonParserLax
        def parser = new JsonSlurper().setType(JsonParserType.LAX)
        def jsonResp = parser.parseText(jsonText)
    }
}

类似地,以下附加的解析器类型在Groovy中可用:

  • JsonParserCharArray解析器基本上采用一个JSON字符串并对底层字符数组进行操作。在值转换期间,它复制字符子数组(称为“斩波”的机制)并单独操作它们。
  • JsonFastParser是JsonParserCharArray的一个特殊变体,是最快的解析器。JsonFastParser也称为索引覆盖解析器,在解析给定的JSON字符串期间,它尽可能努力地避免创建新的字符数组或String实例。它只保留指向底层原始字符数组的指针。此外,它会尽可能晚地推迟对象创建。
  • JsonParserUsingCharacterSource是一个非常大的文件的特殊解析器。它使用一种称为“字符窗口化”的技术来解析具有恒定性能特征的大型JSON文件(大型意味着超过2MB大小的文件)。

文本解析:

import groovy.json.JsonSlurper 

class Example {
    static void main(String[] args) {
        def jsonSlurper = new JsonSlurper()
        def object = jsonSlurper.parseText('{ "name": "John", "ID" : "1"}') 

        println(object.name);
        println(object.ID);
    }
}

以上程序的输出如下:

John 
1

解析整数列表:

我们可以使用每个的List方法,并传递一个闭包。

import groovy.json.JsonSlurper

class Example {
    static void main(String[] args) {
        def jsonSlurper = new JsonSlurper()
        Object lst = jsonSlurper.parseText('{ "List": [2, 3, 4, 5] }')
        lst.each { println it }
    }
}

以上程序的输出如下:

List=[2, 3, 4, 5, 23, 42]

解析基本数据类型列表:

JSON解析器还支持字符串,数字,对象,true,false和null的原始数据类型。JsonSlurper类将这些JSON类型转换为相应的Groovy类型。

import groovy.json.JsonSlurper

class Example {
    static void main(String[] args) {
        def jsonSlurper = new JsonSlurper()
        def obj = jsonSlurper.parseText ''' {"Integer": 12, "fraction": 12.55, "double": 12e13}'''
            
        println(obj.Integer);
        println(obj.fraction);
        println(obj.double); 
    }
}

以上程序的输出如下:

12
12.55
1.2E+14