Gradle 之语言基础 Groovy

96
lijiankun24
0.7 2018.11.30 10:20* 字数 1957

最近在学习 Android 中 Gradle 相关的知识,如果想学好 Gradle,必要的 Groovy 基础是不可少的。Groovy 语言的知识也是非常多的,如果只是想在 Android Gradle 这个范围内使用 Groovy,会 Groovy 的基础即可,Groovy 语言文档。本篇文章主要介绍了 Groovy 中的变量、String、List、Map、类和对象、闭包等内容,示例代码都在 GradleForAndroid

一. Android Gradle 概述

Groovy 是从 Java 衍生出来的,Groovy 的源代码文件 .groovy 也是编译成为 .class 文件,然后运行在 JVM 虚拟机上的。其目标是,不管是作为脚本语言,还是编程语言,都可以简单、直接的使用。在 Android 的 Gradle 中,Groovy 更多的是用于编写脚本。如果会 Java,学习 Groovy 会比较简单,甚至可以混写 Java 和 Groovy 语法。

Groovy 相比 Java 语言来讲,更加的方便灵活,更多的语法糖使编写 Groovy 代码更加的简洁,而且在 Groovy 中具有函数式编程的思想。比如:Groovy 中非常重要的闭包 Closure 概念(类似于 C 语言中的函数指针),可以当做一个函数也执行,也可以当做某个函数的参数传入到函数中去,也可以当做一个函数的返回值返回。

想学好 Gradle,除了必要的 Groovy 知识基础以外,还需要了解其他两个基础知识:Android DSL 和 Gradle DSL。
DSL 是 Domain Specific Language(领域特定语言)的缩写,其定义是:针对某一领域,具有受限表达性的一种计算机程序设计语言。学习 Android Gradle,Android DSL 和 Gradle DSL 也是需要学习的,好在有官方的文档 Android DSL 文档Gradle DSL 文档,学习起来就比较方便。在这篇文章中,不会过多地介绍 Android DSL 和 Gradle DSL,在下篇文章中会介绍。

好了,废话不多说,接下来就来学习 Groovy 的语法基础吧。为了学习的时候,可以执行 gradle 脚本,请先在电脑上配置好 gradle 的环境变量,这样就可以方便地执行 gradle 脚本了。

二. Groovy 语言基础

由于篇幅所限,本篇文章也只能作为一个引子,介绍基础的 Groovy 语言概念,详细的还需要从 Groovy 语言文档 学习。而且我个人认为,如果遇到什么不懂的、不会的,从官方文档上学习是最好的学习途径;或者至少先从官方文档上学习,再去学习其他的资料,将自己学习的和资料的进行对比思考,这样会更有助于个人的成长

为了避免无意义的内容,只介绍和 Java 有区别的地方,相同的地方不作说明。

2.1 变量

  1. Groovy 中声明的变量,默认的修饰符是 public 的
  2. Groovy 中声明变量时,如果一行只声明一个变量则可以省略末尾的 ;,但是如果一行声明了多个变量,变量与变量之间则不可以省略 ;
  3. 在 Groovy 中声明变量,也可以使用关键字 defdef 只是声明了一个变量,变量的实际类型根据该变量的对象决定。def 和 JavaScript 中的 val 有点像,从 def 可以看出 Groovy 也是一门动态语言
  4. Groovy 中字符串 String,可以使用单引号 'String',也可以使用双引号 "String"
  5. 在 Groovy 中的 String,可以通过 ${} 做占位符表达式向字符串中插入值,在 {} 中写表达式或变量都可以,使用 ${} 的字符串必须使用双引号 ""
int version = 1
Boolean isDebug = true
def language = 'groovy'
def message = "Hello from ${language + 1}, the result is ${isDebug}."

task hello {
    doLast{
        println message 
    }
}

上面代码的执行输出是:

> Task :hello
Hello from groovy1, the result is true.

2.2 List

  1. 因为在 Groovy 中没有定义任何集合类,所以 Groovy 中的 List 使用的是 JDK 中的 java.util.List
  2. 在 Groovy 中的一个 List 中可以添加多种类型的对象元素
  3. 创建 List 对象使用 [],而不是 Java 中的 {},防止和 Groovy 中的 闭包 Closure {} 混淆
  4. 可以通过 [index] 的方式修改和访问 List 中的元素
  5. 可以通过 << 向 List 中添加元素,<< 实际是 leftShift() 方法
  6. 可以通过负数,从后向前访问 List 中的元素,比如 [-1] 表示最后一个元素
  7. 可以通过 [index1, index2] 同时访问 List 中的多个元素,返回结果仍是一个List
  8. 可以通过 [index1..index2] 一次性访问 List 中某个范围内的数组,返回结果也是一个 List
ArrayList arrayList = ['arrayOne', 'arrayTwo', 'arrayThree']
LinkedList linkedList = ['linkedOne', 'linkedTwo', 'linkedThree']
List list = [1, 2, true]
def listDef = ['one', 2, true, 4, '5']

task helloList {
    doLast {
        println listDef
        println arrayList
        println linkedList
        println list
        println list[0]
        println list[-1]
        list << 4
        println list[-1]
        println list[1, 3]
        println list[1..3]
    }
}

输出如下所示:

> Task :app:helloList
[one, 2, true, 4, 5]
[arrayOne, arrayTwo, arrayThree]
[linkedOne, linkedTwo, linkedThree]
[1, 2, true]
1
true
4
[2, 4]
[2, true, 4]

2.3 Arrays

Groovy 中的数组和 Java 中的数组区别并不大,也不过多的做介绍

  1. Groovy 中的数组使用 [] 初始化,并不使用 {},防止和 Groovy 中的 闭包 Closure {} 混淆
  2. 数组不支持 << 向 Arrays 中添加元素
String[] arrayStrings = ["one", "two", 'three'];
def arrayInts = [1, 2, 3] as int[]

task hello {

    doLast {
        println arrayStrings[0]
        println arrayStrings[1]
        println arrayStrings[-1]
        // arrayStrings << 'four'   // Arrays 不支持 << 
        println arrayStrings
        println arrayInts
    }
}

输出如下所示:

> Task :hello
one
two
three
[one, two, three]
[1, 2, 3]

2.4 Map

  1. Groovy 中的 Map 是以 : 作为 key 和 value 的连接,并且以 , 做为每一项的分隔符的
  2. Map 中的 key 既可以是字符串也可以是阿拉伯数字
  3. 可以通过 [key].key 的形式访问或向 map 中赋值,访问的时候如果不存在该 key,则会返回 null
  4. 如果以变量作为 key 访问 map 时,记得需要加上 ()
def maps = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
def mapNums = [1: 'one', 2: 'two', 3: 'three', 100: 'four']

def key = 'name'
def mapKey = [key: 'value']
def mapKey1 = [(key): 'value1']

task helloMaps {

    doLast {

        println maps['red']
        println maps.green
        maps['pink'] = '#FF00FF'
        maps.yello = '#FFFF00'
        println maps['pink']
        println maps.yello
        println maps.white

        println mapNums[1]
        println mapNums[100]
        println mapNums[5]

        println mapKey['key']
        println mapKey['name']

        println mapKey1['name']
    }
}

上述代码的输出是

> Task :app:helloMaps
#FF0000
#00FF00
#FF00FF
#FFFF00
null
one
four
null
value
null
value1

2.5 Class 和对象

Groovy 中的 Class 和 Java 中的 Class 区别并不大,主要有以下几个区别

  1. 如果类、方法没有修饰符的话,默认是 public 修饰符的
  2. 如果类中的变量 fields 没有被修饰符修饰的话,会自动成为一个 propertiesproperties 是公有的,并且会自动生成该 properties 的 setter 和 getter 方法
  3. 在 Java 中,文件名和主类的名称必须一致,但是 Groovy 中并没有这个限制,且在一个 Groovy 文件中可以出现多个 public 的类
  4. 在一个 Groovy 文件中可以在类之外定义方法或语句,这种文件就是脚本了
class Student {
    def name
    def age
    private String work
    public String lover

    def Student(String name) {
        this.name = name
    }
}

task helloClass {

    doLast {
        def student = new Student('lijiankun24')
        println student.name
        println student.getAge()
        println student.lover
        // println student.getLover()       // Student 中并没有 getLover() 这个方法
        // println student.getWork()        // Student 中并没有 getWork() 这个方法
    }
}

输出结果如下:

> Task :app:helloClass
lijiankun24
null
null

2.6 函数

Groovy 中的函数和 Java 中的函数并没有太大的区别

  1. 函数一定会有返回值,如果没有显示的使用 return 返回值的话,函数的最后一行语句的执行结果作为值返回,可能返回值是个 null
  2. 如果函数有参数,调用函数的时候,可以省略函数的括号,函数名和参数之间需要用空格间隔;如果函数没有参数,调用函数的时候就不能省略括号
  3. 函数内不可以访问函数外的变量
def message = 'message'

def printMessage () {
    println message
}

void printName(String name) {
    println name
}

void printPerson(String name, age) {
    println "The name is ${name} and the age is ${age}"
}

task helloFunction {
    doLast {
        println printName('xiaoming')

        printPerson  'xiaoming', 20

        // println printMessage() 会执行异常
    }
}

输出结果如下所示:

> Task :app:helloFunction
xiaoming
null
The name is xiaoming and the age is 20

2.7 闭包 Closure

闭包 closure 是 Java 中没有的,也是需要重点学习的,学好 closure 对理解 Android 中的 Gradle 会有莫大的帮助

  1. 闭包 closure 的定义如下,其中 [closureParameters ->] 作为参数部分,是可以省略的
{ [closureParameters -> ] statements }
  1. closure 其实是 Groovy 中 groovy.lang.Closure 的一个类
  2. 闭包 closure 可以访问闭包之外的变量
  3. 闭包 closure 可以有三种调用方式,如下代码所示
  4. 闭包 closure 的参数可以省略,默认是有个 it 参数的
  5. 闭包 closure 也可以作为另一个闭包 closure 的参数
// 闭包可以访问闭包之外的变量
def message = 'closure is good'
def printMessage = {
    println "The message is '${message}'"
}

// 闭包实际上是一个 `groovy.lang.Closure` 类
Closure<Boolean> booleanClosure = {
    return it == 'xiaoming'
}

// 闭包可以省略参数,默认有一个 `it` 的参数
def testClosure = {
    println "I am a closure, the params is ${it}."
}

// 闭包可以有多个参数,参数可以指定类型,也可以不指定类型
def testClosureParams = { name, int age ->
    println "I am a closure, the params is ${name}."
}

// 闭包可以作为另一个闭包的参数
def paramsClosure = { name, closure ->
    if (closure(name)) {
        println 'The input name is xiaoming'
    } else {
        println 'The input name is not xiaoming'
    }
}

task helloClosure {
    doLast {
        printMessage()
        println booleanClosure('xiaoming')
        println booleanClosure('test')

        // 闭包的三种调用方式
        testClosure 'xiaoming'
        testClosure.call('xiaoming')
        testClosure('xiaoming')

        testClosureParams('xiaoming', 20)
        
        // 闭包 booleanClosure 作为闭包 paramsClosure 的参数
        paramsClosure('xiaoming', booleanClosure)
        paramsClosure('test', booleanClosure)

        // 可以在调用闭包的时候才去定义参数闭包的定义,使用非常方便简洁
        paramsClosure('xiaoming', { name ->
            name.toUpperCase() == 'XIAOMING'
        })
    }
}

输出如下所示

> Task :app:helloClosure
The message is 'closure is good'
true
false
I am a closure, the params is xiaoming.
I am a closure, the params is xiaoming.
I am a closure, the params is xiaoming.
I am a closure, the params is xiaoming.
The input name is xiaoming
The input name is not xiaoming
The input name is xiaoming

Groovy 的基础知识就是这么多,如果想学习更多的内容,建议学习 Groovy 文档

Android 相关
Web note ad 1