Groovy 基础

字符串

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 的闭包有thisObjectownerdelegate 三个属性,当你在闭包内调用方法时,由它们来确定使用哪个对象来处理。默认情况下 delegateowner 是相等的,但是 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 的属性和调用它的方法。