概述
又开始了一个新的系列,这个系列学习Gradle,目标就是彻底理解Gradle,主要还是做下自己理解的笔记,防止忘记
配置Groovy环境
我这里用的是Mac,所以简单介绍下mac怎么配置Groovy环境,由于Groovy是运行在java虚拟机上的,所以首先要确定你的电脑有java环境
-
首先去这个地址下载Groovy http://www.groovy-lang.org/download.html
-
然后把下载下来的压缩包,解压到你需要的位置
-
最后修改
.bash_profile
文件
vi ~/.bash_profile
将下面的语句添加进去
export PATH=$PATH:/Users/***/Documents/groovy-2.4.12/bin
然后终端输入
source ~/.bash_profile
groovy -v
看到groovy的版本号表示已经配置环境完成了
然后用VscodeCode
创建一个hello.groovy
的文件,内容如下:
class Example {
static void main(String[] args) {
// 使用 println 打印信息到 stdout
/*除了上面的注释方法外,这里没也是注释信息哦*/
println '测试数据'
println "Hello World";
}
}
运行这个文件
这样就是就算完成了环境的配置
Groovy 语法学习
一些需要提前了解的知识
- Groovy 的注释和java一样
// 或者/**/
- Groovy语句可以不用分号结尾,这个其实是为了代码写起来更加简洁
- Groovy中支持动态类型,就是
定义变量的时候可以不定义类型
,Groovy中定义变量可以使用def
关键字,虽然def不是必须的,但是还是建议使用def,让代码更加清晰
def variable1 = 1 //可以不使用分号结尾
def varable2 = "I am a person"
def int x = 1 //变量定义时,也可以直接指定类型
- 函数定义时,参数的类型也可以不指定
String testFunction(arg1,arg2){
//无需指定参数类型 ...
}
- 除了定义变量不指定类型外,Groovy中函数的返回值也可以是无类型的
//无类型的函数定义,必须使用 def 关键字
def nonReturnTypeFunc(){
last_line //最后一行代码的执行结果就是本函数的返回值
}
//如果指定了函数返回类型,则可不必加 def 关键字来定义函数
String getString(){
return "I am a string"
}
- 函数返回值:Groovy的函数里,可以不使用
ruturn
,如果不使用return的话,那么函数中最后一句代码执行结果设置为返回值
//下面这个函数的返回值是字符串"getSomething return value"
def getSomething(){
"getSomething return value" //如果这是最后一行代码,则返回类型为 String
1000 //如果这是最后一行代码,则返回类型为 Integer
}
如果函数指明了返回值的类型,那么就必须返回正确的类型,否则就报错,如果返回值是动态类型,才可以返回任意数据类型
- Groovy对字符串支持很强大
1 单引号''中的内容严格对应 Java 中的 String,不对$符号进行转义
def singleQuote='I am $ dolloar' //输出就是 I am $ dolloar
2 双引号""的内容则和脚本语言的处理有点像,如果字符中有$号的话,则它会$表达式先求值。
def doubleQuoteWithoutDollar = "I am one dollar" //输出 I am one dollar
def x = 1
def doubleQuoteWithDollar = "I am $x dolloar" //输出 I am 1 dolloar
3 三个引号'''xxx'''中的字符串支持随意换行 比如
def multieLines = ''' begin
line 1
line 2
end '''
- 最后除了每行代码不用加分号外,Groovy中函数调用的时候还可以不加括号
println("test") ---> println "test"
注意:虽然写代码的时候可以函数调用不带括号,但是函数调用如果是Groovy的API那么可以不带括号,如:print方法,否则还是需要带括号的
,因为Groovy对此的支持还是有一些问题的
Groovy中的数据类型
这里我们只介绍和java中不太一样的东西
基本数据类型
作为动态语言,Groovy中所有的事物都是对象,所以int,boolean这些java中的基本数据类型,在Groovy中其实对应的是他们包装数据类型,比如 int - integer,boolean-Boolean
容器类
Groovy中容器其实就三种
- List:链表,其底层对应java中的List接口,一般用ArrayList作为实现类
- Map:键-值表,其底层对应java中的LinkedHashMap
- Range:范围,他其实是List的一种扩展
List
class Example {
static void main(String[] args) {
//定义list,可以是任何类型的元素
def list = [2,"吃",true]
//list元素赋值,不用担心数组越界,如果超过长度list会自动向该索引填充
list[4]="tt"
//遍历list
for (a in list) {
println a;
}
}
}
Map
Map由[:]定义,冒号左边是key,右边是value,key必须是字符串,value可以是任何的对象,key可以加’’,也可以不加,比如 def map = [key1: "测试",key2: true];
这样系统会自动处理成字符串 ‘key’,‘key’
class Example {
static void main(String[] args) {
//定义map
def map = ['key1': "测试",'key2': true];
//访问map中的值
println map.key2;
println map['key1'];
//定义新的map的key
map.anotherkey = "another";
println map.anotherkey;
}
}
看下输出
$ groovy map.groovy
true
测试
another
如果不加’'的话,map的key和变量同名怎么办呢?看下面例子,也就是说直接使用aa
就是简单的字符串,如果需要取变量的值需要用(aa)
的方式取
def aa ="测试";
def map1 = [aa:"11",(aa):22];
println map1.aa;
println map1."测试";
输出
11
22
Range类
Range类是对List的一种扩展
class Text{
static void main(String[] args) {
//包含12345
def range = 1..5;
println range.from;
println range.to;
//包含1234个元素
def range1 = 1..<5;
println range1.from;
println range1.to;
}
}
查看Groovy API技巧
真正写代码的是时候还是要查看 Groovy SDK API的,因为我们不可能记住全部的用法吧
Groovy API文档的地址 http://www.groovy-lang.org/api.html
我们以上面的Range为例,首先需要定位到Range类
然后在API文档查找你需要的使用的函数和属性就行,但是我们发现,这个文档里面并没有,上面使用的from和to
属性的介绍,这是为什么?
我们发现索然没有 from/to属性的介绍,但是却有 getFrom 和 getTo 这俩个函数
原来根据Groovy的规则,假如文件有个 xx 的成员变量,Groovy会自动为他添加 getXx()和setXx()俩个函数,所以当我们看到Range中有getFrom和getTo
的时候,我们就可以确定Range中有from和to
属性
闭包
什么是闭包
闭包英语是Cloure,是Groovy中非常重要的数据类型,他代表了一段可执行代码,如下:
class Example {
static void main(String[] args) {
def closure = {
//闭包是一段代码,所以用花括号圈起来
String param1,int param2->//箭头前面是参数,后面是代码
println param1+param2;//这个是代码
//最后一句是返回值,也可以用return,和Groovy函数用法一样
'返回值'
}
def aa = closure("测试",11);
closure.call("你好",22);
println aa;
}
}
看下输出
测试11
你好22
返回值
也就是说,闭包的格式是
def xxx = {
paramters -> code} //或者
def xxx = {
无参数,纯 code} 这种 case 不需要->符号
调用闭包
闭包对象.call(参数)
或者: 闭包对象(参数)
这就是闭包的定义和使用,还需要注意一点
如果闭包没有定义参数的话,那就会有一个隐藏参数,这个参数的名字是it
,和this
的作用相似,it
代表闭包的参数
def closure1 ={
println "hello,$it"}
closure1("小明");
def closure2 ={
it->println "hello,$it"}
closure2("小红")
}
上面的写法等同于下面写法,看下输出
hello,小明
hello,小红
但是如果闭包中是这种写法,则表示闭包没有参数
def closure3 = {
-> println "text"}
这种写法就不能传参数了,传了的话就会报错
闭包使用需要主要的点
省略圆括号
有些函数最后一个参数是闭包,比如下面:
public static <T> List<T> each(List<T> self, Closure closure)
上面这个函数表示针对List的每一个元素,都会送入闭包做些处理,那该如何使用这个函数呢?
class Example {
static void main(String[] args) {
//定义list,可以是任何类型的元素
def list = [2,"吃",true]
list.each{
println it
}
}
}
上面代码有俩个知识点
- each函数调用的圆括号省略了,在Groovy中当函数的最后一个参数是闭包的话,就可以省略圆括号,比如:
static def text(int a ,String b,Closure closure){
def aa = a + b;
closure(aa);
}
调用text方法
//第一种调用
text(1,'测试',{
println it;
})
//第二种调用
text 2,'你好',{
println it;
}
}
打印结果
1测试
2你好
可以看到上面俩种调用方式,他们的差别就是调用少了括号
这种形式在android中还是很常见的,比如:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
比如这些其实就是闭包的写法,dependencies其实就是一个函数
void dependencies(Closure configureClosure);
这种方式虽然写起来方便,一开始阅读起来还是挺令人困惑的,要花些时间熟悉下
如何确定闭包的参数
还有另一事情比较令人困惑,那就是如何确定闭包的参数,比如刚才的each方法
public static <T> List<T> each(List<T> self, Closure closure)
看到函数,我们只知道要传入一个闭包,但是参数是什么,返回值是什么?
所以说闭包虽然很方便,但是它和使用它的上下文关联性很强,那么我们到底该怎么确定他的参数和返回值呢?
解决方式只能去看文档
文档介绍的是遍历List,将每个元素传递给给定的闭包。
所以这个闭包只有一个参数,就是遍历的元素
所以闭包的使用还是很坑的,很大程度依赖你对API的熟悉程度,所以在最开始,对API的查询是少不了的
脚本类
Groovy可以向java一样,引入其他包的类,比如我在文件夹 com.aa
中创建文件Aa.groovy
package com.aa
class Aa{
String a;
String b;
Aa(String a,String b){
this.a=a;
this.b=b;
}
def print(){
println a+b;
}
}
这个类其实和java的类就比较相似,如果没有加任何权限修饰符(public,privite)那么Groovy中类和变量都是默认就是public修饰符
然后我们在根目录创建另一个文件Bb.groovy
import com.aa.Aa;
Aa aa = new Aa("小明","小红");
aa.print();
Bb文件先 import com.aa.Aa;
然后调用Aa中的print
方法
看下执行Bb之后的结果
$ groovy Bb.groovy
小明小红
脚本到底是什么
在java中,一个类必须要有(class,interface或者其他),不可以不写,但是Groovy可以像写脚本一样,可以直接把想要的事情写入xxx.groovy
文件中,而且可以使用 groovy xxx.groovy 来直接执行文件
IO操作
Groovy中的IO操作比java中的简单一些,Groovy的IO操作其实是在Java IO操作上进行了更为简便的封装,并且使用Closure来简化代码,一下是文档地址
java.io.File: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/File.html
java.io.InputStream: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.html
java.io.OutputStream: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/OutputStream.html
java.io.Reader: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Reader.html
java.io.Writer: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Writer.html
java.nio.file.Path: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/nio/file/Path.html
读文件
File
直接查看API文档 java.io.File: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/File.html
文件内容
你好啊
哈哈哈
class Example {
static void main(String[] args) {
//创建文件
def file = new File("text.txt");
//输出文件的每一行
file.eachLine{
String line ->
println line;
}
//文件内容一次性读出,返回类型为 byte[]
byte[] aa = file.getBytes()
String bb = new String(aa);
println bb;
}
}
输出
你好啊
哈哈哈
你好啊
哈哈哈
InputStream
首先查看Api文档http://docs.groovy-lang.org/latest/html/groovyjdk/java/io/InputStream.html
//获取InputStream流
def ism = file.newInputStream()
byte[] cc = ism.getBytes()
String dd = new String(cc);
println dd;
//使用闭包操作InputStream,以后在gradle中都是用这种方式
file.withInputStream{
ism1 ->
byte[] ee = ism1.getBytes()
String ff = new String(ee);
println ff
//操作 ism. 不用 close。Groovy 会自动替你 close
}
输出
你好啊
哈哈哈
你好啊
哈哈哈
写文件
继续看文档 http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/OutputStream.html
def srcFile = new File("text.txt")
def targetFile = new File("copy.txt")
targetFile.withOutputStream{
os->
srcFile.withInputStream{
ins->
//利用 OutputStream 的<<操作符重载,完成从 inputstream 到 OutputStream //的输出
os << ins
}
}
XML操作
Groovy中操作XML也是非常的简洁,首先提供一个xml文件
<response version-api="2.0">
<value>
<books>
<book available="20" id="1">
<title>Don Xijote</title>
<author id="1">Manuel De Cervantes</author>
</book>
<book available="14" id="2">
<title>Catcher in the Rye</title> <author id="2">JD Salinger</author>
</book>
<book available="13" id="3">
<title>Alice in Wonderland</title>
<author id="3">Lewis Carroll</author>
</book>
<book available="5" id="4">
<title>Don Xijote</title>
<author id="4">Manuel De Cervantes</author>
</book>
</books>
</value>
</response>
开始写代码
class Example {
static void main(String[] args) {
def booksData = new XmlParser().parse("text.xml");
// 访问第一个book元素的available属性
def ava = booksData.value.books.book[0].@available
println ava
//访问第二个book元素的title
def data = booksData.value.books.book[2].title.text();
println data
//访问第一个book元素的id属性
def id = booksData.value.books.book[0].@id
println id
println "---------------------"
//遍历boos标签打印title
booksData.value.books.each{
books->
books.each{
book ->
println book.title.text();
}
}
}
}
输出
20
Alice in Wonderland
1
---------------------
Don Xijote
Catcher in the Rye
Alice in Wonderland
Don Xijote