Gradle学习笔记之Groovy简单使用

news2024/12/26 3:37:14

简介

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))
        }
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/61254.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ArcGIS基础:使用线段分割面数据操作

本操作主要是实现线要素对面要素的分割。 先看一下原始数据&#xff0c;如下所示&#xff0c;2个面&#xff0c;1条线&#xff0c;面被线贯穿过去。 首先进行【面转线】操作&#xff0c;以提取面要素的边界线&#xff0c;如下所示 提取结果如下所示&#xff1a; 然后进行【…

java认证与证书

本文内容主要来自《Java加密与解密的艺术》 目前主要有JKS和PEM两种编码格式文件。 JKS&#xff08;Java Key Store&#xff09;&#xff0c;Java原生的密钥库/信任库文件。**PEM&#xff08;Privacy Enbanced Mail&#xff0c;隐私增强邮件&#xff09;**是使用多种加密方法提…

2022-12-04一周学习

这周基本上还是在对前端学习的更多一点&#xff0c;主要是之前没有重视vue3的学习,现在在补上来&#xff0c;学习了vue3的一些知识&#xff0c;前端的权限管理&#xff0c;设置路由守卫&#xff0c;pinia&#xff0c;还学习了redis的一些基本操作&#xff0c;之前只是照搬了别人…

Linux的线程创建

对于任何一个进程来讲&#xff0c;即便我们没有主动去创建线程&#xff0c;进程也是默认有一个主线程的。线程是负责执行二进制指令的&#xff0c;它会根据项目执行计划书&#xff0c;一行一行执行下去。进程要比线程管的宽多了&#xff0c;除了执行指令之外&#xff0c;内存、…

二、演练领域驱动的设计过程

一、业务分析&#xff1a;统一语言与事件风暴 1、统一语言&#xff1a; 客户明白自己的领域知识也就是业务&#xff0c;以及自己需要解决的问题&#xff0c;也叫做痛点&#xff0c;但是不知道技术。技术人员知道技术&#xff0c;但是不了解客户的业务。所以两者交流起来往往会…

[附源码]计算机毕业设计物品捎带系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

finereport公式帮助

1 if(inarray($$$,ds1.select(销售员))<$TOPN,$$$,"其他")&#xff0c;将第 N 个销售员之后的所有销售员合并为其他&#xff0c; 2 "["((roundup($$$/$num)-1)*$num1)"~"(roundup($$$/$num)*$num)"]" 3 SQL语句用if语句&#xff0c…

HTML网页设计作业:文化网站设计——基于HTML古典中国风工艺美术网页设计(9页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

SpringBoot @InitBinder注解绑定请求参数

参考资料 springMVC之InitBinder 和 ValidatorspringMVC之InitBinder的用法1springMVC之InitBinder的用法2 目录一. 作用二. 前期准备三. Get请求 URL传值处理3.1 前台-test16.html3.2 Controller层3.3 效果四. Post请求 表单传值 自定义日期属性绑定器4.1 前台-test16.htm…

华为机试 - 任务最优调度

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 给定一个正整数数组表示待系统执行的任务列表&#xff0c;数组的每一个元素代表一个任务&#xff0c;元素的值表示该任务的类型。 请计算执行完所有任务所需的最短时间。 任务执行规则如下: 任务可…

Springboot RabbitMq源码解析之RabbitListener注解 (四)

文章目录1.RabbitListener注解介绍2.EnableRabbit和RabbitBootstrapConfiguration3.RabbitListenerAnnotationBeanPostProcessor4.对RabbitListener注解的解析5.RabbitListenerEndpointRegistrar1.RabbitListener注解介绍 RabbitListener是Springboot RabbitMq中经常用到的一个…

D-023 DVI硬件电路设计

DVI硬件电路设计1 简介1.1 连接器1.2 接口信号定义1.3 DVI的分类1.4 DVI规格2 硬件设计实战3 硬件设计要点3.1 注意事项3.2 补充说明3.3 VGA 和 DVI 优缺点1 简介 DVI(Digital Visual Interface)是一种数字视频接口&#xff0c;它是基于TMDS (Transition Minimized Differenti…

MFC列表控件的用法(基于对话框的编程)

目录 一、List Control列表控件属性 1.List Control 2.View属性 二、OnInitDialog初始化列表 1.创建List Control的变量 2.找OnInitDialog ​3. InsertColumn插入表头 4. InsertColumn设置对齐方式和列宽 5. 设置List的正文内容 ​6.循环结构创建列表 7.设置列表整行…

Windows内核--子系统(3.5)

到底什么是子系统? 子系统是用户层概念。在Windows内核之上&#xff0c;如果想要执行类UNIX应用程序&#xff0c;就是POSIX子系统&#xff0c;如果要类似OS/2环境&#xff0c;就是OS/2子系统。 如何能模拟出不同子系统呢? 一般需要子系统用户态应用程序和相关DLL支援。 对于W…

腾讯云服务器mysql安装

1.选择mysql版本 2.安装mysql源 sudo wget https://repo.mysql.com//mysql80-community-release-el7-1.noarch.rpm 3.下载mysql.rpm源 wget https://repo.mysql.com//mysql80-community-release-el7-1.noarch.rpm 4.安装下载好的rpm包 sudo rpm -ivh mysql80-community-rele…

PCB入门介绍与电阻电容电感类元件的创建

摘自凡亿教育 目录 一、PCB入门介绍 二、电阻电容电感类元件的创建 1.绘制电阻的原理图库 2.绘制电容的原理图库 3.绘制电感的原理图 一、PCB入门介绍 1.EDA工具 Cadence Allegro :IC-芯片设计 Mentor PADS:做消费类电子产品、手机、机顶盒、平板电脑 Altium Designer…

多线程初阶(二)

目录 前言&#xff1a; synchronized 解析 可重入和不可重入问题 解析 Java中线程安全类 死锁问题 解析 解决死锁问题 解析 内存可见性 解析 volatile关键字 解析 wait&#xff0c;notify 解析 小结&#xff1a; 前言&#xff1a; 针对上篇文章讲到的线程安全…

VSCode\\VS2017下CPP环境的配置

VSCode下C环境配置一些问题VSCode下配置C环境&#xff1a;VSCode与boost总结&#xff1a;坑位待填&#xff1a;VSCode中3个json文件的作用&#xff1a;环境配置出现的问题以及解决VS2017 配置 C环境VS配置boost库包含项目中的自定义的.hpp文件&#xff0c;.h文件VSCode下配置C环…

公众号网课题库接口

公众号网课题库接口 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转&#xff09;…

4.验证面试高频问题整理(附答案)

目录 Q76.package如何使用 Q77.如何在子类中调用父类中的方法 Q78.bit[7:0]和byte有什么区别 Q79.类中的方法和类外的方法有什么区别 Q80.如何将类中的方法定义在类外 Q81.modport的用途是什么 Q82.struct和union的异同 Q83.$rose和posedge区别 Q84.如何在fork...join结…