Groovy是基于JVM的一种动态语言,语法与Java相近,上手较快。Groovy完全兼容Java。 又增加了很多动态类型和灵活的特性,是一门比较灵活的动态脚本语言。
变量 Groovy中通过def
定义变量,无需指定变量类型,自动判断。
数据类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 task printDef << {def str1 = "str" def str2 = 'str' def str3 = '''str 23 45''' def intV = 1 def doubleV = 2.0 def floatV = 3.0 f println("字符串 ${str1} ${str2} 数值 ${intV} ${doubleV} ${floatV}" ) } ./gradlew printDef
println
输出到控制台,只有双引号标记的${ }
才可以生效。
集合 List
Groovy在Java的集合类基础上进行了拓展与增强,并对原有集合完美兼容。
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 task printList << { def numList = [1 ,2 ,3 ,4 ,5 ,6 ,7 ] def linkList = [1 ,2 ,3 ] as LinkedList println numList[0 ] println numList[-1 ] println numList[0. .2 ] println numList[-1. .-3 ] numList << 5 numList.add(5 ) numList.remove(1 ) numList.each{ print "${it}," } numList.eachWithIndex{ it,i -> print("${i}," ) } println numList.find{ it>3 } println numList.findAll{ it>3 } println numList.findIndexOf{ it ==4 } println numList.findFirstIndexOf{it==4 } println numList.findLastIndexOf{it==4 } numList.sort() numList.unique() }
Map
Map用法与List类似,只不过它的值是一个KV键值对。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 task PrintMap << { def map = [one: "111" ,two: "222" ,three: "333" ] println map["one" ] println map.one map.each { println "Key:${it.key} value:${it.value}" } println map.containKey("one" ) println map.containValue("222" ) map.clear() }
Range
Groovy提供的一种容器类,是对List的拓展
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 task printRange << { def range = 1. .5 print range println range.size() println range.get(1 ) println range.contains(3 ) println range.first() println range.from() println range.last() println range.to() range.add(6 ) range.remove(0 ) range.clear() range.each {println it} }
操作符 **
运算符
等同于 2^3 = 8
?.
占位符
用于避免空指针异常
1 2 def person = new Person() println person?.name?:""
.@
操作符
直接跳过写的getXX()
获取对应值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Person { String name Integer age = 10 int getAge() { age+10 } } task printClass << { Person p = new Person(); p.name = "wxy" println p.name println p.@age println p.age }
三目运算符 1 2 3 4 5 6 def namedef result = name==null ?"null":namedef result = name?:"null" print result
###asType
数据类型转换
1 2 3 4 String string = "23" def toInt = string as int def toInt = string.asType(Integer)
<=>
比较操作符1 2 3 assert (1 <=> 1 ) == 0 assert (1 <=> 2 ) == -1 assert (2 <=> 1 ) == 1
*.
展开运算符
得到原集合中各元素的组合后的集合
1 2 3 4 5 6 7 8 9 class Person { String name int age }def persons = [new Person("a" ,1 ),new Person("b" ,2 ),new Person("c" ,3 )]def names = persons*.name def names = persons.collect{it.name}
*.
操作符是空安全的,支持传入null
with
操作符
简化对同一对象进行赋值的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Person { String name int age int score } task testWith << { Person person = new Person() person.with { name="a" age=12 score=60 } }
方法
Groovy中的方法与Java方法相似,但是提供了更便利的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 task printMethod << { add(1 ,3 ) add 1 ,4 println minus (5 ,2 ) }def add(int a,int b){ println a+b }static int minus(a,b){ println "a=${a} b=${b}" a-b }
语句后面的分号可以省略
方法中的括号可以省略 类似注释1
return 可以省略掉 类似注释2 最后一行代码为返回值的最终结果
参数类型可以忽略掉 类似注释3
默认方法修饰符为public
。
类
Groovy类类似于Java类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 task printClass << { Person p = new Person(); p.increaseAge(2 ) p.name="wxy" println p.name println p.age }class Person { String name Integer age =10 int getAge(){ age } def increaseAge(Integer years){ this .age+=years } }
默认类的修饰符为public
没有可见修饰符的会自动生成对应的getter/setter
方法
类不需要与它的源文件有相同的名称,建议采用相同的名称
语句 断言
用于进行单元测试
1 2 3 tasl test << { assert 1 +2 ==6 }
for语句
循环语句
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 task testFor << { def x= 0 for (i in 0. .3 ){ x+=i } for (i in 0. .<4 ){ x+=i } println x x = 0 def list = [0 ,1 ,2 ,3 ] for (i in list){ x+=i } println x x = 0 ; def map =[a: 1 ,b: 2 ,c: 3 ] for ( i in map.values){ x+=i } println x }
time语句
用于进行循环输出
1 2 3 4 5 4. times { print it } 输出0 1 2 3
switch语句
选择语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 static def returnSwitch(x){ def result = "" switch (x){ case "ok" : result = "found ok" break case String: result = "isString" break case 1. .10 : result = "in range" break case Integer: result = "is Integer" break case [1 ,2 ,3 ,4 ]: result = "is List" break default: result = "default" return result } }
switch
除了Java支持的数据类型Integer、String
以外,还支持数组类型、区间、列表等
捕获异常
写法同Java一致
1 2 3 4 5 6 7 8 9 10 11 12 try { } catch (EOFException e) { e.printStackTrace() } try { } catch (e) { e.printStackTrace() }
I/O操作
对原有Java I/O操作进行了封装,简化了使用方法
文件读取 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 task testFileRead << { def filePath = "$path" def file = new File(filePath) println file.text file.eachLine { println it } def line = "" file.withReader {reader -> while (line = reader.readLine()){ println line } } file.withReader("utf-8" ){reader-> while (line = reader.readLine()){ println line } } def is = file.newInputStream() is.eachLine { println it } is.close() file.withInputStream { stream -> stream.eachLine { println it } } }
Reader
:即使读取过程中抛出异常也可以自动关闭IO操作
文件写入 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 task testFileWrite << { def file = new File("%path" ) file.withWriter("utf-8" ){writer-> writer.writeLine "Hello" writer.writeLine "," writer.writeLine "World" } file << '''Hello , World''' def bytes = [66 ,22 ,11 ] as byte [] def out = file.newOutputStream() out.write(bytes) out.flush() out.close() file.withOutputStream {stream-> stream.write(bytes) stream.write(bytes) } def out = file.newPrintWriter() out.write("sasd" ) out.write("sdds" ) out.flush() out.close() file.withPrintWriter { writer -> writer.append("ssss" ) writer.println("dfff" ) writer.write("12333" ) } }
文件遍历
可用于检测文件是否重复,例如代码中的重复资源引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 task testFileEach << { def file = new File("$path" ) file.eachFile { file-> println file.name } file.eachFileRecurse{file-> println file.name } file.eachFileRecurse(FileType.FILES){file-> println file.name } }
FileType
包含以下三种类型:
FileType.ANY
:可获取所有类型,包含文件、目录
FileType.FILES
:只能获取文件类型
FileType.DIRECTORIES
:只能获取文件夹类型
闭包
Groovy中一个重要的特性,是DSL 的基础。使得代码变得灵活、轻量、可复用 。
基础样式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 task testClosure << { customEach{ iii-> print iii } }static def customEach(closure){ for (int i in 1. .10 ){ closure(i) } }
多参数
如果闭包中只有一个参数,默认可以使用it
。也可以自己指定名称。多参数情况时,就需要列举出所有参数
1 2 3 4 5 6 7 8 9 10 11 12 13 task testClosure << { eachMap{k,v-> print "${k} : ${v}" } }static def eachMap(closure){ def map =["1" :1 ,"2" :2 ] map.each { closure(it.key,it.value) } }
闭包调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def closure1 = { String name,int age -> println "${name} is ${age}" } closure1("wxy" ,111 ) 或 closure1.call("wxy" ,111 ) 特殊实例:def closureSpecial = { -> println "special" } closureSpecial.call() closureSpecial()
闭包委托
Groovy的闭包有thisObject、owner、delegate
三个属性,当你在闭包内调用方法时,由他们来确定使用哪个对象来处理。
对象
含义
方法
thisObject
对应于定义闭包的那个类 如果在内部类中定义,指向的是内部类
getThisObject()
owner
对应于定义闭包的那个类或闭包 如果在闭包中定义,对应闭包,与thisObject
一致
getOwner()
delegate
默认与owner
一致 可以进行自定义拓展更多功能
getDelegate()
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 OuterClass { class InnerClass { def outerClosure = { def innerClosure = { } printMsg("innerClosure" , innerClosure) printMsg("outerClosure" , outerClosure) } void printMsg(flag,closure){ def thisObject = closure.getThisObject() def ownerObject = closure.getOwner() def delegate = closure.getDelegate() println("${flag} this : ${thisObject.toString()}" ) println("${flag} owner : ${ownerObject.toString()}" ) println("${flag} delegate : ${delegate.toString()}" ) } } def callInnerMethod(){ def innerClass = new InnerClass() innerClass.outerClosure.call() println("outerClosure toString ${innerClass.outerClosure.toString()}" ) } } task printBibao << { new OuterClass().callInnerMethod() } .....................输出结果......................... > Task : CustomPlugin: printBibao innerClosure this : OuterClass$InnerClass@4 ee95fee innerClosure owner : OuterClass$InnerClass$_closure1@1177369 d innerClosure delegate : OuterClass$InnerClass$_closure1@1177369 d outerClosure this : OuterClass$InnerClass@4 ee95fee outerClosure owner : OuterClass$InnerClass@4 ee95fee outerClosure delegate : OuterClass$InnerClass@4 ee95fee outerClosure toString OuterClass$InnerClass$_closure1@1177369 d
根据上述的输出结果可以对应出上面的表格。
delegate
委托中最关键的就是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 38 39 40 41 42 43 44 45 46 task printClosure << { Main main = new Main() Man man = new Man(name: "sd" ,age: 11 ) println man.toString() main.cc.delegate = man main.cc.call() println man.toString() }class Man { String name int age static void eat(food) { println "eat ${food}" } @Override String toString() { return "Man{ name = ${name} age = ${age} }" } }class Main { static void eat(food){ println "Main eat $food" } def cc = { name = "wxy" age = 12 eat("ss" ) } } 输出结果: Man{ name = sd age = 11 } Main eat ss Man{ name = wxy age = 12 } Man{ name = sd age = 11 } eat ss Man{ name = wxy age = 12 }
上述的执行结果,最终调用到了Main.eat()
而不是Man.eat()
,考虑到这个情况,Closure
提供了setResolveStrategy()
来控制调用同名方法的来源。
setResolveStrategy()
设置对应属性
参数含义
Closure.OWNER_FIRST(默认值 )
优先在owner中寻找,没有就去delegate中寻找
Closure.DELEGATE_FIRST
优先在delegate中寻找,没有就去owner中寻找
Closure.OWNER_ONLY
只在owner中寻找
Closure.DELEGATE_ONLY
只在delegate中寻找
Closure.TO_SELF
???
在上述实例中,owner
相当于Main
,delegate
相当于Man
引用 Apache-Groovy
搞定Groovy闭包
Groovy 使用完全解析