• 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
    
    • 1
    • 2

    在Idea中创建groovy项目

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

    Groovy基本语法

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

    类的定义

    class Test {
        int a = 1
        String name
        boolean flag
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Groovy脚本:

    def username = 'szc'
    
    println(username)
    
    • 1
    • 2
    • 3

    编译后,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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    反编译分析

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

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

    def username = 'szc'
    
    println(username)
    
    class Person {
        int age
        String name
    }
    
    //class Demo01 { // 类名不能和文件名一致
    //    
    //}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    def count = 1
    
    class Person {
        def age
        def name
    
        public def getName() {
            return name
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    类的使用

    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 +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    引号和字符串:

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

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

    ${s}
    """
    def s4 = '''
    
    三但引号字符串,支持换行操作,但不支持\\$引用:
    
    ${s}
    '''
    println s1
    println s2
    println s3
    println s4
    
    /*
    单引号字符串,不支持换行操作和$引用,$(s)
    双引号字符串,不支持换行操作,但支持$引用,test
    
    
    三双引号字符串,支持换行操作,支持$引用:
    test
    
    
    三但引号字符串,支持换行操作,但不支持\$引用:
    ${s}
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    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
    
    • 1
    • 2
    • 3
    • 4

    可见,单引号字符串类型就是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
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    映射

    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
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    类导入和异常处理

    跟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()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    闭包

    定义

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

    {
    [params ->] statements
    }
    
    • 1
    • 2
    • 3

    调用

    先将闭包赋值给一个变量,再通过变量名()或变量名.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
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

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

    // 无参闭包做参数
    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
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

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

    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))
            }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    iwemeta元宇宙:阿里首任COO:如何打造销售铁军
    C++中的List
    adobe国际认证证书有用吗?
    spring下配置tomcat jdbc pool 报找不到“com.mysql.jdbc.Driver“类
    架构设计的五个核心要素
    基于springboot实现汽车租赁管理系统项目演示【项目源码+论文说明】分享
    字符串函数
    ElementUI编辑表格单元格与查看模式切换的应用
    Node.js的readline模块 命令行交互的模块
    dreamweaver网页设计作业制作 学生个人网页猫眼电影 WEB静态网页作业模板 大学生个人主页博客网页代码 dw个人网页作业成品
  • 原文地址:https://blog.csdn.net/qq_37475168/article/details/128172066