字符串
在 Groovy
中,分号是不必需的,所以很多 Gradle
脚本没有分号,这是 Groovy
的特性,而不是 Gradle
的。在 Groovy
中,单引号和双引号都可以表示字符串,但是单引号
标记的是纯粹的字符串变量,而双引号可以做运算,具体实例如下:
task printStringClass << {
def str1 = '单引号'
def str2 = "双引号"
println "单引号定义的字符串类型:"+str1.getClass().name
println "双引号定义的字符串类型:"+str2.getClass().name
}
task printStringVar << {
def name = "张三"
println '单引号的变量计算:${name}'
println "单引号的变量计算:$name"
println "单引号的变量计算:${name}"
println "单引号的变量计算:${1+1}"
}
输出:
运算格式如下:一个美元符号跟一对花括号,花括号里放表达式(${name + age}),只有一个变量的时候可以省略花括号($name)。
集合
List
先看代码:
task printList << {
def numList =[1,2,3,4,5,6]
println numList.getClass().name
println numList[1]//访问第二个元素
println numList[-1]//访问最后一个元素
println numList[-2]//访问倒数第二个元素
println numList[1..3]//f访问第二个到第四个元素
numList.each {
println it
}
}
结果:
由结果可知,numList
是一个 ArrayList
类型, Groovy
提供了下标索引的方式访问数据,就像数组一样,除此之外,还提供了负下标索引。负下标索引代表从右边开始,-1 就代表从右侧数第一个,-2 代表从右侧数第二个,以此类推; 1..3
这种是一个范围索引,中间用两个 “.” 分开。
上述代码中的 each
是方法,用来遍历数据的,it
代码正在遍历的数据本身,传过来的参数是一个闭包类型的。
Map
Map
用法和 List
很像,只不过它的值是一个 K:V
键值对,代码如下:
task printlnMap << {
def map1 =['width':1024,'height':768]
println map1.getClass().name
println map1['width']
println map1.height
map1.each {
println "Key:${it.key},Value:${it.value}"
}
}
结果:
由结果可知,map1 是一个 LinkedHasMap
类型,map1 的 KEY 可以不带引号,但是如果用 map1[]方式输出的话,一定要带引号。Map 遍历的对象是一个 Map.Entry
的对象。上述代码用到了双引号的运算。
方法
括号可以省略
在 Groovy
中 ,当方法的参数不少于一个的时候,可以省略(),例如如下代码:
task invokeMethod << {
method1(1,2)
method1 1,2 //省略括号
}
def method1(int a,int b){
println a+b
}
Groovy 中的方法都是调用省略()的形式的。
return可以省略
当没有 return 的时候,Groovy 会把方法执行过程中的最后一句代码作为其返回值,代码如下:
task printMethodReturn << {
def add1 = method2 1,2
def add2 = method2 5,3
println "add1:${add1},add2:${add2}"
}
def method2(int a,int b){
if(a>b){
a
}else{
b
}
}
输出结果:add1:2,add2:5
,说明是有返回值的,而是最后一行代码作为返回值。
代码块可以作为参数
代码块: 一段被{}包围的代码,其实就是闭包。 Groovy
允许其作为参数传递,以集合的 each
方法为例,它接受的参数其实就是一个闭包。
numList.each({println it}) //呆板的写法是这样的
numList.each({ //格式化之后是这样的
println it
})
numList.each { //省略括号之后是这样的
println it
}
所以 each
是一个方法调用,关于闭包,我们后面再说。
JavaBean
先看代码:
task helloJavaBean << {
Person p = new Person()
println "名字是:${p.name}"
p.name = "张三"
println "名字是:${p.name}"
println "年龄是:${p.age}"
}
class Person {
private String name
public int getAge(){
12
}
}
上述代码能正常输出名字和年龄,所以在 Groovy
中,我们不需要调用 getter/setter
方法 ,底层会通过 getter/setter
方法处理我们需要的值,上述的 age
只会获取到值,不能设置值,因为没给出 setter
方法 ,name
是成员变量,系统会自动添加 getter/setter
方法的。
闭包
闭包是 Groovy
非常重要的特性,它是 DSL
的基础。闭包其实是一段代码块,我们可以仿集合的 each
实现一个类似的闭包功能。
task helloClosure << {
//使用我们自定义的闭包
customEach {
println it
}
}
def customEach(Closure closure){
//模拟一个有10个元素的集合,开始迭代
for(int i in 1..10){
closure(i)
}
}
运行上述代码,就会遍历,跟之前的 List 遍历是一样的效果,customEach
接收一个闭包参数,闭包后面跟()就是执行了,如果只有一个参数,默认就是 it
变量。当有多个参数时, it
就不能表示了,我们需要把参数一一列出:
def eachMap (Closure closure){
def map = [name : "zhangsan",age:18]
map.each {
closure(it.key ,it.value)
}
}
task helloClosure << {
eachMap{ k,v ->
println "${k} is ${v}"
}
}
例子中为闭包传递了两个参数,所以不能用 it
了,要显式声明出来,->
是用于把闭包的参数和主体区分出来的,这是闭包的格式。
闭包委托
Groovy
闭包的强大之处在于它支持闭包方法的委托。 Groovy
的闭包有thisObject
、 owner
、delegate
三个属性,当你在闭包内调用方法时,由它们来确定使用哪个对象来处理。默认情况下 delegate
和 owner
是相等的,但是 delegate
是可以被修改的,这个功能是非常强大的, Gradle 中的闭包的很多功能都是通过修改 delegate
实现的。
thisObject
的优先级是最高的,默认优先使用 thisObject
来处理闭包中调用的方法,其实 thisObject
就是这个构建脚本的上下文,它和脚本中的 this
对象是相等的。闭包的处理顺序如下:thisObject > owner > delegate
。
在 DSL
中,一般会指定 delegate
为当前的 it
,这样我们在闭包内就可以对该 it
进行配置,或者调用其方法。
task configClosure << {
person {
personName = "张三"
personAge = 20
println it.personName
//dumpPerson()
}
}
class Person {
String personName
int personAge
def dumpPerson(){
println "name is ${personName},age is ${personAge}"
}
}
def person(Closure<Person> closure){
Person p = new Person();
closure.delegate = p
//委托模式优先
closure.setResolveStrategy(Closure.DELEGATE_FIRST);
closure(p)
}
上述代码就是用当前的 it
,即 Person
实例配置了 delegate
,所以我们可以在闭包内设置 Person
的属性和调用它的方法。