0%

Groovy笔记

概述

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

Groovy中有以下特点:

  • 同时支持静态和动态类型
  • 支持运算符重载
  • 对正则表达式的本地支持
  • 可以使用现有的Java库及Java语法
  • 不需要分号
  • 可省略return关键字,默认用最后一个表达式为返回
  • 使用命名的参数初始化beans和默认的构造器:new Server(name: "Obelix", cluster: aCluster)
  • Groovy里的is()方法等同于Java里的==,Groovy中的==是更智能的equals()
  • 在同一个bean中使用with()来重复某一个操作:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 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()
    }

基本语法

1
2
3
4
5
class Test {
static void main(String[] args) {
println('Hello World.')
}
}

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

1
2
3
4
5
6
7
8
9
10
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中的字符串是字符的有序序列,字符串索引从零开始,还允许负索引从字符串的末尾开始计数。

1
2
3
4
5
6
7
8
9
10
11
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”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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语言支持正常的算术运算符任何语言。

范围运算符:

1
2
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。

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

1
2
3
4
5
6
7
8
9
10
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();
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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中还有一个规定来指定方法中的参数的默认值。 如果没有值传递给参数的方法,则使用缺省值。 如果使用非默认和默认参数,则必须注意,默认参数应在参数列表的末尾定义。

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

1
2
3
4
5
6
7
8
9
10
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类中,目的是确保文本文件的每一行都被读取。

1
2
3
4
5
6
7
8
9
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类输出文本到一个文件中:

1
2
3
4
5
6
7
8
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属性来获取:

1
2
3
4
5
6
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选项:

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

创建目录

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

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

删除文件

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

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

复制文件

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

1
2
3
4
5
6
7
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函数显示机器上的驱动器:

1
2
3
4
5
6
7
8
class Example { 
static void main(String[] args) {
def rootFiles = new File("test").listRoots()
rootFiles.each {
file -> println file.absolutePath
}
}
}

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

1
2
3
4
5
6
7
class Example {
static void main(String[] args) {
new File("E:/Temp").eachFile() {
file->println file.getAbsolutePath()
}
}
}

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

1
2
3
4
5
6
7
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() 返回原始列表的排序副本。

多重赋值和多返回值:

1
2
3
4
5
6
7
// 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() 返回此地图中包含的值的集合视图。

键可以是任意类型:

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

Date

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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”表达式本地支持正则表达式,引号中包含的文本表示用于比较的表达式:

1
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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
}

闭包

概述

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

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

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

闭包的形参

1
2
3
4
5
6
7
8
9
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");
}

闭包和变量

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

1
2
3
4
5
6
7
8
9
10
11
12
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

在方法中使用闭包

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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]

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

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

集合和字符串中的闭包

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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,来实现方法的委托功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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:

用法实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 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(领域定义语言)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<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,可以使用下述方法解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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("*******************************")
}
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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字符串。
1
2
3
4
5
6
7
8
import groovy.json.JsonOutput

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

以上程序的输出如下:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

以上程序的输出如下:

1
[{"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解析器类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
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大小的文件)。

文本解析:

1
2
3
4
5
6
7
8
9
10
11
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);
}
}

以上程序的输出如下:

1
2
John 
1

解析整数列表:

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

1
2
3
4
5
6
7
8
9
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 }
}
}

以上程序的输出如下:

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

解析基本数据类型列表:

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

1
2
3
4
5
6
7
8
9
10
11
12
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);
}
}

以上程序的输出如下:

1
2
3
12
12.55
1.2E+14