2--Gradle入门 - Groovy简介、基本语法
Gradle 需要 Groovy 语言的支持,所以本章节主要来介绍 Groovy 的基本语法。
1.Groovy 简介
在某种程度上,Groovy 可以被视为Java 的一种脚本化改良版,Groovy 也是运行在 JVM 上,它可以很好地与 Java 代码及其相关库进行交互操作。它是一种成熟的面向对象编程语言,既可以面向对象编程,又可以用作纯粹的脚本语言。大多数有效的 Java 代码也可以转换为有效的 Groovy 代码,Groovy 和 Java 语言的主要区别是:完成同样的任务所需的Groovy 代码比 Java 代码更少。其特点为:
-  功能强大,例如提供了动态类型转换、闭包和元编程(metaprogramming)支持 
-  支持函数式编程,不需要main 函数 
-  默认导入常用的包 
-  类不支持 default 作用域,且默认作用域为public。 
-  Groovy 中基本类型也是对象,可以直接调用对象的方法。 
-  支持DSL(Domain Specific Languages 领域特定语言)和其它简洁的语法,让代码变得易于阅读和维护。 
-  Groovy 是基于Java 语言的,所以完全兼容Java 语法,所以对于java 程序员学习成本较低。详细了解请参考:http://www.groovy-lang.org/documentation.html 
 
 
2. Groovy 安装 SDK
下载Groovy SDK
官网下载地址:https://groovy.apache.org/download.html

下载后为一个 zip 包,如下:

解压缩 SDK

将 SDK 解压之后,下面就可以配置环境变量了。
配置环境变量
变量名:GROOVY_HOME
变量值:解压后的目录
添加path路径中:%GROOVY_HOME%\bin

测试查询 Groovy 版本
C:\Users\Administrator>groovy -v
Groovy Version: 4.0.3 JVM: 1.8.0_91 Vendor: Oracle Corporation OS: Windows 10执行如下:

查询版本之后,可以配置完成了。
3. Idea 创建 Groovy 项目
Idea创建项目的时候选择Groovy
File - New - Project / Module(本文以建立Project为例) - 选择Groovy - 点击Creater(选择下载的Groovy SDK包) - 下一步命名Project - 点击OK。
此时即建立了Groovy项目。




配置项目工程的 out 输出目录
在 Project 工程配置 out 输出目录。

在模块的路径设置继承 Project 的 out 路径

编写 Demo 输出 HelloWorld
创建 Groovy 类

编写 Demo
package test
/**
 * @author Aron.li* @date 2022/7/6 8:57
 */
class demo {
    static void main(String[] args) {
        println("Hello,World!Groovy!");
    }
}执行代码如下:

查看生成的 demo 执行类

可以看到实现了 GroovyObject 类
编写 Demo 脚本
groovy 也可以使用脚本的方式来实现,不用写成类:

package test
def str1 = 'hello world'
printf("message: ${str1}")查看生成的输出类:

可以看到,如果是脚本的写法,那么生成类则是继承 Script 类。
4. Groovy 基本语法
创建一个以 .groovy 为后缀的文件,我们可以在这文件中像开发java代码一样简单的去使用 groovy,并且 groovy 提供的语法更加简洁。
我们可以完全像开发 Java 代码一样去编写 Groovy,也可以根据 Groovy 的语法来简化编写。
第一个 Hello world 程序
class Example {
   static void main(String[] args) {
      // 使用 println 就可打印输出,并且类和方法默认就是public,可以不用写
      println('Hello World');
   }
}运行

Hello WorldGroovy 的导入语句
和 Java 一样,都是使用 Import 进行导入
import groovy.xml.MarkupBuilder  // Import 进行导入需要的类
def xml = new MarkupBuilder()   // def 就是动态类型,在Groovy可以不用指定具体的类型,就像js中的var一样在编译的 Groovy 字节码文件中,Groovy 已经默认帮我们导入了一些jar包,这些 jar 包可以不用再显示的导入
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.BigDecimalGroovy 的注释
和 Java 一样,支持单行 // 和多行注释 /**/
// Using a simple println statement to print output to the console
/* This program is the first program
      This program shows how to display hello world */Groovy 的分号
; 分号,可以用来区分不同的代码块。
在 Groovy 编写中可以,可以省略分号符
Groovy 的标识符
和 Java 一样,标识符就是变量名,声明规则和 Java 一样,可以以字母开头,美元或下划线。但不能以数字开头。
Groovy 的关键字
大部分关键字和 Java 中的用法一样
| as | assert | break | case | 
|---|---|---|---|
| catch | class | const | continue | 
| def | default | do | else | 
| enum | extends | FALSE | Finally | 
| for | goto | if | implements | 
| import | in | instanceof | interface | 
| new | pull | package | return | 
| super | switch | this | throw | 
| throws | trait | TRUE | try | 
| while | 
数据类型
Groovy 的内置数据类型和 Java 一样有8种。byte、short、int、long、float、double、char、boolean
字符串:String
并且都有其对应的封装类
变量
变量也和 Java 一样,除了使用基本数据类型和引用类型,还可以使用def动态数据类型来声明变量。
// 和java的区别就是多了,def动态类型
def a = 1; // 在编译时会自动转化为int
def a = 'aa';运算符
大部分运算符和 Java 一样,如:算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符
范围运算符
与 Java 不同点在于,新增了 范围运算符
def range = 0..5范围运算符通过..来指定其开始和结束的范围。
上面示例就简单的定义了一个,从0到5的范围。
/**
 * @author Aron.li* @date 2022/7/11 7:59
 */
class RangeDemo {
    public static void main(String[] args) {
        // 定义 5~10 的范围
        def range = 5..10
        // 打印范围
        println(range)
        // 取范围中的数据
        println(range.get(2))
        // 遍历范围数据
        range.forEach( e -> {
            print(e + ', ')
        })
    }
}运行

运算符优先级
| 运算符 | 名称 | 
|---|---|
| ++ ,-- ,+ ,- | 预增/减(自增/减),一元加,一元减 | 
| *, /, % | 乘法,除法,取模 | 
| +,- | 加法,减法(二元) | 
| ==,!=, <=> | 等于,不等于,比较运算符 | 
| & | 二进制/位运算符与 | 
| ^ | 二进制/位异或 | 
| ` | ` | 
| ! | 逻辑非 | 
| && | 逻辑与 | 
| ` | |
| =,+=,-=,*=,/=,%=,**= | 各种赋值运算符 | 
循环
Groovy 中的循环和 Java 中一样,包含循环跳出和结束循环等
while、for、break、continuewhile 语句
package test.basicUsage
/**
 * 循环Demo
 *  while、for、break、continue
 *
 * @author Aron.li* @date 2022/7/11 8:17
 */
class CycleDemo {
    public static void main(String[] args) {
        // while demo
        println("while demo .................")
        int i = 0
        while (i < 5){
            if ( i == 4) break
            if ( i == 2) continue
            println("i = " + i)
            i ++
        }
    }
}运行如下:

for in 语句
在 Java 中我们常常使用foreach来遍历
for(String str : strList){
    ...
}而在 Groovy 中提供了for in语句,其使用方法和 Java 一样,只是关键字不同
for(def str in strList){
    println(str);
}示例代码如下:
// for in
println("for in .................")
def strList = ['hello', 'world']
for (def str in strList){
    println(str)
}运行结果如下:
for in .................
hello
worldfor 语句
// for
println("for .................")
for (int j = 0; j < 5; j++) {
    println("j = " + j)
}运行结果如下:
for .................
j = 0
j = 1
j = 2
j = 3
j = 4continue
// continue
println("continue .................")
for (int j = 0; j < 5; j++) {
    if (j == 3) continue
    println("j = " + j)
}运行结果如下:
continue .................
j = 0
j = 1
j = 2
j = 4break
// break
println("break .................")
for (int j = 0; j < 5; j++) {
    if (j == 3) break
    println("j = " + j)
}运行结果如下:
break .................
j = 0
j = 1
j = 2条件语句
Groovy 中的条件语句和 Java 中的一样,其关键字如下
if、else、switch等
包括其嵌套使用等
if 语句
package test.basicUsage
/**
 * 条件语句
 */
class ConditionDemo {
    public static void main(String[] args) {
        // if 条件语句
        println("if 条件语句............")
        int a = 20
        if (a < 10){
            println("a < 10, a = " + a)
        } else if (a > 20){
            println("a > 20, a = " + a)
        } else {
            println("else, a = " + a)
        }
    }
}运行结果如下:
if 条件语句............
else, a = 20Switch语句
// Switch语句
println("Switch语句 ............")
int b = 2
switch (b){
    case 1:
    println("The value of a is One")
    break
    case 2:
    println("The value of a is Two")
    break
    case 3:
    println("The value of a is Three")
    break
    case 4:
    println("The value of a is Four")
    break
    default:
        println("The value is unknown")
    break
}运行结果如下:
Switch语句 ............
The value of a is Two嵌套Switch语句
// 嵌套 Switch 语句
int i = 0
int j = 1
switch(i) {
    case 0:
        switch(j) {
            case 0:
                println("i is 0, j is 0")
                break
            case 1:
                println("i is 0, j is 1")
                break
            default:
                println("nested default case!!")
        }
        break
    default:
        println("No matching case found!!")
}运行结果如下:
i is 0, j is 1案例
1.案例1:基本语法
groovy 中使用 def 定义变量、方法,不建议使用具体的类型:

package test.basicUsage
/**
 * def 定义各种变量
 * - groovy 中使用 def 定义变量、方法,不建议使用具体的类型
 *
 * @author Aron.li* @date 2022/7/16 15:38
 */
class defDemo {
    static def msg (str){
        // 如果没有return,则会以最后一行返回消息
        "msg: ${str}"
    }
    static def add(num1, num2){
        return num1 + num2
    }
    static void main(String[] args) {
        // 输出msg方法的返回值
        println(msg("hello world"))
        // Example of an Integer using def
        def a = 100
        println(a)
        // Example of an float using def
        def b = 100.10
        println(b)
        // Example of an Double using def
        def c = 100.101
        println(c)
        // Example of an String using def
        def d = "HelloWorld"
        println(d)
        // Example of an Func return using def
        def sum = add(100, 10)
        println(sum)
    }
}注意事项案例
为了更加方便理解,下面我定义一个类,然后再写一个 script 脚本来调用该类的属性、方法:
-  Demo1BasicNotice 
package test.demo
class Demo1BasicNotice {
/**--------------------------------------------------
 * 1.groovy中使用def 定义属性、方法,def支持动态类型声明
 * 2.单行注释:// 多行注释: /**
 * 3.gradle语句最后的;(分号)是可以省略的
 * 4.groovy可以为属性自动生成getter、setter方法
 * 5.方法声明时:参数类型、返回值类型、return关键字可以省略,方法调用时,再不引起歧义的地方,可以省略()
 * 6.变量应用时:在不引起歧义的前提下{}也可以省略,再容器引起歧义的地方就不能省略{}
 * 7.对象属性赋值时:
 *      方式1: 对象.属性名=
 *      方式2: 对象["属性名"]=
 *      方式3: 对象.属性setter方法()
 *      方式4:  具名构造器的方式
 *   读取属性值:
 *      方式1: 对象.属性名
 *      方式2: 对象["属性名"]
 *      方式3: 对象.属性getter方法
 *
 * --------------------------------------------------
 */
    // 定义属性
    def name = "李小龙"
    def age = 10
    def desc = "描述信息"
    def address = "地址信息"
    // 定义方法
    def sendMessage(msg){
        "msg: $msg"
    }
    def sum(num1, num2){
        "sum = ${num1 + num2}"
    }
}-  Demo1BasicNoticeScript.groovy 
package test.demo
// 获取对象
def notice = new Demo1BasicNotice()
// 设置属性、读取属性
notice.age = 30
println("notice.age = $notice.age")
notice["desc"] = "demo 描述信息"
println("desc = ${notice["desc"]}")
notice.setAddress("深圳市南山区")
println("address = ${notice.getAddress()}")
// 使用方法
def message = notice.sendMessage("发送消息...")
println(message)
def sum = notice.sum(10, 15)
println(sum)执行如下:

2. 案例 2:引号说明
package test.demo
//---------------------------- 字符串 ------------------------------
def desc="测试"
def str1='单引号, 不支持变量引用 ${desc},不支持换行操作 '
println(str1)
def str2 = "双引号,支持变量应用 ${desc}, 不支持换行操作"
println(str2)
def str3 = """
模板字符串: ${desc}, 支持换行操作\n
换行测试.....
"""
println(str3)
// 基本数据类型也可以作为对象使用,可以调用对象的方法
println(str1.getClass().toString())
println(str2.getClass().toString())
println(str3.getClass().toString())执行如下:

3.案例 3:三个语句结构
Groovy 支持顺序结构从上向下依次解析、分支结构(if..else、if..else if ..else..、switch..case、for、while、do..while)
具体参考官网:http://www.groovy-lang.org/semantics.html#_conditional_structures
4. 案例 3:类型及权限修饰符
Groovy 中的类型有:
-  原生数据类型及包装类 

-  类、内部类、抽象类、接口 
-  注解 
-  Trait: 可以看成是带有方法实现的接口 
权限修饰符: public、protected、private
拓展:Groovy 类与 Java 类之间的主要区别是:
-  没有可见性修饰符的类或方法自动是公共的(可以使用一个特殊的注释来实现包的私有可见性)。 
-  没有可见性修饰符的字段将自动转换为属性,不需要显式的 getter 和 setter 方法。 
-  如果属性声明为 final,则不会生成 setter。 
-  一个源文件可能包含一个或多个类(但是如果一个文件不包含类定义的代码,则将其视为脚本)。脚本只是具有一些特殊约定的类,它们的名称与源文件相同(所以不要在脚本中包含与脚本源文件名相同的类定义)。 
提 示 : 有 关 Groovy 中 各 种 各 样 的 数 据 类 型 和 权 限 修 饰 符 及 Goovy 与 Java 区 别 请 参 考 :
http://www.groovy-lang.org/objectorientation.html#_modifiers_on_a_property
5. 案例 5:集合操作
Groovy 支持List、Map 集合操作,并且拓展了 Java 中的API,具体参考如下方法:
List:
-  add():添加某个元素plus():添加某个list 集合
-  remove():删除指定下标的元素removeElement():删除某个指定的元素removeAll(): 移除某个集合中的元素
-  pop():弹出list 集合中最后一个元素putAt():修改指定下标的元素
-  each():遍历
-  size(): 获取list 列表中元素的个数
-  contains(): 判断列表中是否包含指定的值,则返回 true
Map:
-  put():向map 中添加元素
-  remove():根据某个键做移除,或者移除某个键值对
-  +、-:支持 map 集合的加减操作
-  each():遍历map 集合
请参考官网:http://www.groovy-lang.org/syntax.html#_number_type_suffixes
提示:可以把不同的基本类型添加到同一集合中。
List 增删查改:
package test.demo
//---------------------------list增删查改操作--------------------
//----------------------1.增----------------------
//1.1. 增:在集合中添加元素
println("1.1. 增:在集合中添加元素")
def list = [5, 6, 7, 8]
println(list)
assert list instanceof List
list.add(12)
println(list)
println(list.size())
//1.2. 增:集合与集合相加
println("1.2. 增:集合与集合相加")
def list2 = [1, 2, 3, 4]
def list3 = list.plus(list2)
println(list) // 原来的list集合不改变
println(list3) // 集合相加会生成新的集合
//----------------------2.删-------------------------
//2.1. 删:删除下表为2的元素
println("2.1. 删:删除下表为2的元素")
println("删除之前的list: ${list}")
list.remove(2)
println("删除之后的list: ${list}")
//2.2 删:删除集合中指定的元素
println("2.2 删:删除集合中指定的元素")
println("删除之前的list: ${list}")
list.removeElement(12)
println("删除之后的list: ${list}")
//2.3 删:从list集合中移除list3集合中的元素
println("2.3 删:从list集合中移除list3集合中的元素")
def list4 = [6, 8]
list.removeAll(list4)
println(list)
//---------------------------3.改-----------------------
println("3.list的修改")
list.putAt(2, 10) // 等效于 list[2]=10
println(list)
//---------------------------4.查------------------------
//4.1 遍历list
println("4.1 遍历list")
[1, 2, 3].each { println("Item: {$it}") }
//4.2 获取list的大小
println("4.2 获取list的大小: ${list.size()}")
//4.3 判断list是否包含指定的值
println("4.3 判断list是否包含指定的值: ${[1, 2, 3].contains(2)}")Map增删查改
//---------------------------map增删查改操作--------------------
// Key 可以不适用引号,可以使用单引号 '',也可以使用双引号 ""
def map = [J: "Java", "K": "Kotlin", 'G': "Groovy"]
//----------------------1.增----------------------
println("----------------------1.增----------------------")
map.put("P", "Python")
println("map: ${map}")
def map2 = [C: "C++"]
map.putAll(map2)
println("map: ${map}")
//----------------------2.删----------------------
println("----------------------2.删----------------------")
map.remove("P") // 根据某个Key做移除
map.remove("J", "Java") // 移除某个键值对
println("map: ${map}")
//----------------------3.改----------------------
println("----------------------3.改----------------------")
// "-" "+" 操作符
map3 = map - ["K": "Kotlin"]
println("map3: ${map3}")
map4 = map + [G: "Gradle"] // key相同则会覆盖
println("map4: ${map4}")
//----------------------4.查----------------------
println("----------------------4.查----------------------")
map.each { key, value ->
    {
        println("key: $key, value: $value")
    }
}6.案例 6:类导入
Groovy 遵循 Java 允许 import 语句解析类引用的概念。
import groovy.xml.MarkupBuilder 
def xml = new MarkupBuilder() 
assert xml != nullGroovy 语言默认提供的导入
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这样做是因为这些包中的类最常用。通过导入这些样板代码减少了。
参考官网地址:
http://www.groovy-lang.org/structure.html#_imports
7. 案例 7:异常处理
Groovy 中的异常处理和 java 中的异常处理是一样的。
def z 
try {
    def i = 7, j = 0 
    try {
        def k = i / j 
        assert false
    } finally {
        z = 'reached here'
    }
} catch ( e ) {
    assert e in ArithmeticException 
    assert z == 'reached here'
}参考官网地址:
http://www.groovy-lang.org/semantics.html#_try_catch_finally
8. 案例 8:闭包
闭包:Groovy 中的闭包是一个开放的、匿名的代码块,它可以接受参数、也可以有返回值。闭包可以引用其周围作用域中声明的变量。
语法:{ [closureParameters -> ] statements }
其中[ closureParameters-> ]是一个可选的逗号分隔的参数列表,参数后面是  Groovy 语句。参数类似于方法参数列表, 这些参数可以是类型化的,也可以是非类型化的。当指定参数列表时,需要使用-> 字符,用于将参数与闭包体分离。
参考:http://www.groovy-lang.org/closures.html
//闭包体完成变量自增操作
{ item++ }
//闭包使用 空参数列表 明确规定这是无参的
{ -> item++ }
//闭包中有一个默认的参数[it],写不写无所谓
{ println it }
{ it -> println it }
//如果不想使用默认的闭包参数it,那需要显示自定义参数的名称
{ name -> println name }
//闭包也可以接受多个参数
{ String x, int y ->
    println "hey ${x} the value is ${y}"
}
//闭包参数也可是一个对象
{ reader ->
    def line = reader.readLine() 
    line.trim()
}闭包调用方式:闭包是 groovy.lang.Closure 的实例。它可以像任何其他变量一样分配给一个变量或字段。
闭包对象(参数)
闭包对象.call(参数)
def isOdd = { int i -> i%2 != 0 } 
assert isOdd(3) == true
assert isOdd.call(2) == false
def isEven = { it%2 == 0 } 
assert isEven(3) == false 
assert isEven.call(2) == true特殊说明:可以把闭包当作一个对象,作为参数传递给方法使用
package test.demo
/**=================================================
 * 闭包:
 *      定义:是一个开放的、匿名的代码块,它可以接受参数、也可以有返回值。闭包可以引用其周围作用域中声明的变量。
 *      语法:{ [closureParameters -> ] statements }
 *      调用:
 *          第一步:将闭包赋值给一个变量
 *          第二步:变量名()、变量名.call()
 *
 *       闭包在实际开发中的使用:作为方法的参数使用
 =================================================*/
// 1. 有参数的闭包
println("1. 有参数的闭包")
// 定义闭包
def running = { who ->
    println("$who running start .....")
    println("$who running end .....")
}
// 调用闭包
running()
running.call("小明")
// 2. 将闭包作为对象参数,传递给闭包
println("2. 将闭包作为对象参数,传递给闭包")
// 2.1 定义无参闭包
println("2.1 无参闭包")
def run(Closure closure) {
    println("run start....")
    // 执行无参闭包
    closure()
    println("run end....")
}
// 执行闭包
run {
    println("running....")
}
// 2.2 定义有参闭包
println("2.2 有参闭包")
def caculate(Closure closure) {
    def num1 = 1
    def num2 = 3
    println("caculate start....")
    // 执行有参闭包
    closure(num1, num2)
    println("caculate end....")
}
// 执行有参闭包
caculate { x, y -> println("计算结果为: $x + $y = ${x + y}") }执行如下:




















