Gradle学习笔记之Groovy简单使用

简介

groovy可以当成java的脚本化改良版,同样运行于JVM之上,可以很好地和java代码及相关库进行交互,既可以面向对象编程,也可以用作纯粹的脚本语言。Groovy支持动态类型转换、闭包、元编程、函数式编程、默认作用域为public(不支持default)、基本类型为对象(可以直接调用对象的方法)、支持领域特定语言DSL和其他简洁语法,并且完全兼容java语法。

官方文档下载地址,下载好压缩包后,解压、将bin目录的路径加入到path环境变量中即可,而后在命令行中验证:

C:\Users\songzeceng>groovy -v
Groovy Version: 4.0.2 JVM: 1.8.0_231 Vendor: Oracle Corporation OS: Windows 10

在Idea中创建groovy项目

创建新项目时,选择Groovy,然后在Groovy library中选择groovy解压目录(已有Groovy library则不用),再点击Next:
在这里插入图片描述
而后给项目起个名字,点击Finish:
在这里插入图片描述
最后,会得到如下所示的groovy项目:
在这里插入图片描述

Groovy基本语法

可参见官方文档
在这里插入图片描述

类的定义

class Test {
    int a = 1
    String name
    boolean flag
}

Groovy脚本:

def username = 'szc'

println(username)

编译后,Groovy类产生的字节码,反编译成java代码后,内容如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.transform.Generated;
import groovy.transform.Internal;
import java.beans.Transient;

public class Test implements GroovyObject {
    private int a;
    private String name;
    private boolean flag;

    @Generated
    public Test() {
        byte var1 = 1;
        this.a = var1;
        MetaClass var2 = this.$getStaticMetaClass();
        this.metaClass = var2;
    }

    @Generated
    @Internal
    @Transient
    public MetaClass getMetaClass() {
        MetaClass var10000 = this.metaClass;
        if (var10000 != null) {
            return var10000;
        } else {
            this.metaClass = this.$getStaticMetaClass();
            return this.metaClass;
        }
    }

    @Generated
    @Internal
    public void setMetaClass(MetaClass var1) {
        this.metaClass = var1;
    }

    @Generated
    public int getA() {
        return this.a;
    }

    @Generated
    public void setA(int var1) {
        this.a = var1;
    }

    @Generated
    public String getName() {
        return this.name;
    }

    @Generated
    public void setName(String var1) {
        this.name = var1;
    }

    @Generated
    public boolean getFlag() {
        return this.flag;
    }

    @Generated
    public boolean isFlag() {
        return this.flag;
    }

    @Generated
    public void setFlag(boolean var1) {
        this.flag = var1;
    }
}

反编译分析

Groovy脚本得到的反编译java代码如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//


import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;

public class Demo01 extends Script {
    public Demo01() {
    }

    public Demo01(Binding context) {
        super(context);
    }

    public static void main(String... args) {
        InvokerHelper.class.invoke<invokedynamic>(InvokerHelper.class, Demo01.class, args);
    }

    public Object run() {
        Object username = "szc";
        return this.invoke<invokedynamic>(this, username);
    }
}

可见两者的父类是不同的。我们可以在Groovy脚本中定义类,但类名不能和文件名一致:

def username = 'szc'

println(username)

class Person {
    int age
    String name
}

//class Demo01 { // 类名不能和文件名一致
//    
//}

实际上,更推荐用def定义变量、字段或方法:

def count = 1

class Person {
    def age
    def name

    public def getName() {
        return name
    }
}

类的使用

def p = new Person(hometown: "Anyang") // 字段赋值方式1:具名构造器
p.age = 25 // 字段赋值方式2:对象.字段名 = 字段值
p["name"] = "szc" // 字段赋值方式3:对象["字段名"] = 字段值
p.setGender("male") // 字段赋值方式4:对象.set字段名(字段值)

println p.metaClass.class.name // 不引起歧义的情况下,方法调用的()可以省略
println p.toString()
println p.getName()
println p.say()

class Person {
    def age
    def name
    def gender
    def hometown

    public def getName() {
        return name
    }

    public def say() {
        "${name} said, 'Oh my Jesus!'" // 方法体最后一句,即为方法返回值
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name=" + name +
                ", gender=" + gender +
                ", hometown=" + hometown +
                '}';
    }
}

引号和字符串:

def s = "test"
def s1 = '单引号字符串,不支持换行操作和$引用,$(s)'
def s2 = "双引号字符串,不支持换行操作,但支持\$引用,${s}"
def s3 = """

三双引号字符串,支持换行操作,支持$引用:

${s}
"""
def s4 = '''

三但引号字符串,支持换行操作,但不支持\\$引用:

${s}
'''
println s1
println s2
println s3
println s4

/*
单引号字符串,不支持换行操作和$引用,$(s)
双引号字符串,不支持换行操作,但支持$引用,test


三双引号字符串,支持换行操作,支持$引用:
test


三但引号字符串,支持换行操作,但不支持\$引用:
${s}
*/

输出一下四种字符串的类型:

println s1.class.name // java.lang.String
println s2.class.name // org.codehaus.groovy.runtime.GStringImpl
println s3.class.name // org.codehaus.groovy.runtime.GStringImpl
println s4.class.name // java.lang.String

可见,单引号字符串类型就是String,双引号字符串的类型则是GStringImpl

列表

Groovy中的列表就是ArrayList,但是支持+、-、+=、-=这些操作符,以便向列表里添加或删除新的列表,遍历时,支持以闭包的形式遍历:

def list1 = [1, 2, 3, 4, 5]
println(list1) // [1, 2, 3, 4, 5]
list1.add(6)
println(list1) // [1, 2, 3, 4, 5, 6]
list1 = list1.plus([7, 8, 9, 10])
list1 += [11, 12, 13, 14]
println(list1) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

list1.remove(list1.size() - 1)
list1 = list1 - [11, 12]
list1.removeAll([11, 10])
println(list1) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 13]
println(list1.pop()) // 弹出第一个元素,输出为1
println(list1) // [2, 3, 4, 5, 6, 7, 8, 9, 13]
list1.putAt(15, 20) // 给指定位置设置元素值,不必和已有数据连续
list1[18] = 92 // 给指定位置设置元素值的另一种方式
println(list1) // [2, 3, 4, 5, 6, 7, 8, 9, 13, null, null, null, null, null, null, 20, null, null, 92]

// 遍历列表
list1.each {
    if (it instanceof Integer && it != null) { // it即当前元素
        def x = it * 2
        println(x)
    } else {
        println(0)
    }
}
// 输出:
/*
4
6
8
10
12
14
16
18
26
0
0
0
0
0
0
40
0
0
184
*/

映射

Groovy中的映射是LinkedHashMap,同样支持+、-、+=、-=这些操作符,遍历时,支持以闭包的形式遍历:

def map = ["Name": "szc", "Age": 25] // 映射初始化
map.put("Gender", "male") // 往映射里添加键值对,键已存在则覆盖
map += ["Hometown": "Anyang", "School": "UESTC"] // 往映射里添加新的映射,通过操作符的方式
println(map) // [Name:szc, Age:25, Gender:male, Hometown:Anyang, School:UESTC]

map.remove("School") // 从映射里删除键对应的键值对,无此键则跳过
map.remove("Hometown", "Anyang") // // 从映射里删除键和值对应的键值对,无此键值对则跳过
map = map - ["Gender": "male"] // 从映射里删除子集映射,通过操作符的方式
println(map) // [Name:szc, Age:25]

// 遍历映射,以键值对的方式
map.each {key, value -> {
    println("key: $key, value: $value")
}}

// 输出:
/*
key: Name, value: szc
key: Age, value: 25
*/

// 遍历映射,以entry的方式
map.each {
    println("key: ${it.key}, value: ${it.value}")
}
// 输出:
/*
key: Name, value: szc
key: Age, value: 25
*/

类导入和异常处理

跟java中类似:

// 类导入
import groovy.xml.MarkupBuilder

def builder = new MarkupBuilder()

// 异常捕获方式1:和java里完全一样
try {
    def x = 1, y = 0
    def t = x / y
} catch (e) {
    e.printStackTrace()
} finally {
    println ("here we are at finally")
}

// 异常捕获方式2:try-catch中嵌套try-finally,和方式一等效
try {
    try {
        def x = 1, y = 2
        def t = x / y
        println(t)
    } finally {
        println ("here we are at finally")
    }
} catch (e) {
    e.printStackTrace()
}

闭包

定义

闭包是一个开放的匿名代码块,可以有参数(默认为it)和返回值,可以引用周围作用域中声明的变量,语法:

{
[params ->] statements
}

调用

先将闭包赋值给一个变量,再通过变量名()或变量名.call()调用:

def name = "test"

def f1 = {
    Integer x, Integer y, Integer z -> {
        println("$name, x = $x, y = $y, z = $z")
        Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2))
}}

def ret = f1(1, 2, 5)
println(ret)
println f1.call(2, 3, 4)

// 输出:
/*
test, x = 1, y = 2, z = 5
5.477225575051661
test, x = 2, y = 3, z = 4
5.385164807134504
*/

实际开发中,经常把闭包当成一个对象,传入给方法:

// 无参闭包做参数
def run(Closure closure) {
    println("Start running.......")
    closure() // 执行闭包
    println("Stop running.......")
}

run { // 传入无参闭包
    println("Running....")
    // -> println("Running....") 也可以这样指定无参闭包,上面的方式带有隐式参数it
}

// 有参闭包做参数
def distance(Closure closure, int x1, int x2, int y1, int y2) {
    closure(x1, x2, y1, y2)
}

// 传入有参闭包和参数,得到返回结果并输出
def ret1 = distance({ int x1, int x2, int y1, int y2 ->
    {
        Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2))
    }
}, 8, -2, 4, 9)


println(ret1)

// 输出:
/*
Start running.......
Running....
Stop running.......
11.180339887498949
*/

如果方法中的有参闭包参数是参数列表的最后一个,那么调用该方法时,可以将有参闭包写在方法调用外面:

def distance2(int x1, int x2, int y1, int y2, Closure closure) { // 有参闭包为方法的最后一个参数
    closure(x1, x2, y1, y2)
}

println(distance2(8, -2, 4, 9) { // 将有参闭包体写在方法调用外面
    int x1, int x2, int y1, int y2 ->
        {
            Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2))
        }
})
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值