Gradle之Groovy语言的简单认识(二)

笔记来源于:
https://blog.csdn.net/singwhatiwanna/article/details/76084580 http://liuwangshu.cn/application/gradle/3-groovy.html

1. Groovy简介:

Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy代码能够与Java代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy 可以使用其他 Java 语言编写的库。

2. Groovy和Java的关系

Groovy是一种JVM语言,它最终是要变异成class文件然后在JVM上执行,所以Java语言的特性Groovy都支持,我们完全可以混写Java和Groovy。

那么Groovy的优势是什么呢?简单来说,Groovy提供了更加灵活简单的语法,大量的语法糖以及闭包特性可以让你用更少的代码来实现和Java同样的功能。比如解析xml文件,Groovy就非常方便,只需要几行代码就能搞定,而如果用Java则需要几十行代码。

3. Groovy的变量和方法声明

在Groovy中,通过def关键字来声明变量和方法,比如:

class Demo1{
    def a=1;
    def b="hello world";
    def c=1;
    def hello(){
        println("hello world");
        return 1;
    }
}

在Groovy中,很多东西都是可以省略的,比如

  1. 语句后面的分号是可以省略的。
  2. 变量的类型和方法的返回值也是可以省略的。
  3. 方法调用时,括号也是可以省略的。
  4. 甚至语句中的return都是可以省略的。

上面的代码也可以写成如下形式

class Demo2 {
    def a = 1
    def b = "hello world"
    def int c = 1

    def hello() {
        println "hello world" //方法调用省略括号
        1;//方法返回值省略return
    }

    def hello(String msg) {
        println(msg)
    }
    //方法省略类型参数
    int hello(msg) {
        println(msg)
        return 1
    }
    //方法省略参数类型
    int hello1(msg) {
        println msg
        return 1//这个return不能省略
        println "done"
    }
}

总结:

  1. 在Groovy中,类型是弱化的,所有的类型都可以动态推断,但是Groovy仍然是强类型的语言,类型不匹配仍然会报错。
  2. 在Groovy中很多东西都可以省略,所以寻找一种自己喜欢的写法。
  3. Groovy中的注释和Java中相同。

4. Groovy的数据类型

在Groovy中,数据类型有:

  1. Java中的基本数据类型
  2. Java中的对象
  3. Closure(闭包)
  4. 加强的List、Map等集合类型
  5. 加强的File、Stream等IO类型

类型可以显示声明,也可以用def来声明,用def声明的类型Groovy将会进行类型推断。

基本数据类型和对象在这里不用赘述,和Java中的一致,只不过在Gradle中,对象默认的修饰符为public。下面主要说下String、闭包、集合和IO等。

4.1. String

String的特色在于字符串的拼接,比如

class StringDemo {
    /**
     * 这里出现了字符串插值,除了单引号和三单引号字符串,所有的字符串都可以插入Groovy 表达式,三引号字符串可以保留文本的换行和缩进格式。
     * 插值实际就是替换字符串中的占位符,占位表达式是由${}包含起来或者是由$开头的.表达式,
     * 当GString 被传了一个带有String参数的方法 时,通过调用toString()方法,可以把占位符里
     * 面的表达式解析为真正的值。
     * @return
     */
    def hello() {
        def a = 1
        def b = "hello"
        def c = "a=${a}, b=${b}"
        println(c)
    }
}


outputs:
a=1, b=hello
4.2. 闭包

Groovy中有一种特殊的类型,叫做Closure,翻译过来就是闭包,这是一种类似于C语言中函数指针的东西。闭包用起来非常方便,在Groovy中,闭包作为一种特殊的数据类型而存在,闭包可以作为方法的参数和返回值,也可以作为一个变量而存在。

如何声明闭包?

{ parameters -> 
   code
}

闭包可以有返回值和参数,当然也可以没有。下面是几个具体的例子:

def closure = { int a, String b ->
   println "a=${a}, b=${b}, I am a closure!"
}

// 这里省略了闭包的参数类型
def test = { a, b ->
   println "a=${a}, b=${b}, I am a closure!"
}

def ryg = { a, b ->
   a + b
}

closure(100, "renyugang")
test.call(100, 200)
def c = ryg(100,200)
println c

闭包可以当做函数一样使用,在上面的例子中,将会得到如下输出:

a=100, b=renyugang, I am a closure!
a=100, b=200, I am a closure!
300

另外,如果闭包不指定参数,那么他会有一个隐含的参数it

//这里省略了闭包的参数类型   
def test = {
    println "find ${it},I am a closure!"
}
test(100)

outputs:  
find 100,I am a closure!

闭包的一个难题是如何确定闭包的参数,尤其当我们调用Groovy的API时,这个时候没有其他办法,只有查询Groovy的文档:

http://www.groovy-lang.org/api.html

http://docs.groovy-lang.org/latest/html/groovy-jdk/index-all.html
下面会结合具体的例子来说明如何查文档。

4.3 List和Map

Groovy加强了Java中的集合类,比如List、Map、Set等。

  • 1. List的使用如下
def emptyList = []

def test = [100, "hello", true]
test[1] = "world"
println test[0]
println test[1]
test << 200
println test.size

outputs:
100
world
4

List还有一种看起来很奇怪的操作符<<,其实这并没有什么大不了,左移位表示向List中添加新元素的意思,这一点从文档当也能查到。

You can access elements of the list with the [] subscript operator (both for reading and setting values) with positive indices or negative indices to access elements from the end of the list, as well as with ranges, and use the << leftShift operator to append elements to a list

def letters = ['a', 'b', 'c', 'd']

assert letters[0] == 'a'     //1
assert letters[1] == 'b'

assert letters[-1] == 'd'    //2
assert letters[-2] == 'c'

letters[2] = 'C'             //3
assert letters[2] == 'C'

letters << 'e'               //4
assert letters[ 4] == 'e'
assert letters[-1] == 'e'

assert letters[1, 3] == ['b', 'd']  //5         
assert letters[2..4] == ['C', 'd', 'e']   //6 
  1. Access the first element of the list (zero-based counting)
  2. Access the last element of the list with a negative index: -1 is the first element from the end of the list
  3. Use an assignment to set a new value for the third element of the list
  4. Use the << leftShift operator to append an element at the end of the list
  5. Access two elements at once, returning a new list containing those two elements
  6. Use a range to access a range of values from the list, from a start to an end element position

其实Map也有左移操作,这如果不查文档,将会非常费解。

  • 2. Map使用如下:
def emptyMap = [:]
def test = ["id":1, "name":"renyugang", "isMale":true]
test["id"] = 2
test.id = 900
println test.id
println test.isMale

outputs:
900
true

可以看到,通过Groovy来操作List和Map显然比Java简单的多。

这里借助Map再讲述下如何确定闭包的参数。比如我们想遍历一个Map,我们想采用Groovy的方式,通过查看文档,发现它有如下两个方法,看起来和遍历有关:

image

可以发现,这两个each方法的参数都是一个闭包,那么我们如何知道闭包的参数呢?当然不能靠猜,还是要查文档。

image

通过文档可以发现,这个闭包的参数还是不确定的,如果我们传递的闭包是一个参数,那么它就把entry作为参数;如果我们传递的闭包是2个参数,那么它就把key和value作为参数。

按照这种提示,我们来尝试遍历下:

def emptyMap = [:]
def test = ["id":1, "name":"renyugang", "isMale":true]

test.each { key, value ->
   println "two parameters, find [${key} : ${value}]"
}

test.each {
   println "one parameters, find [${it.key} : ${it.value}]"
}

outputs:
two parameters, find [id : 1]
two parameters, find [name : renyugang]
two parameters, find [isMale : true]

one parameters, find [id : 1]
one parameters, find [name : renyugang]
one parameters, find [isMale : true]

这里贴出官方给的例子:

  1. 遍历List:

    image

  2. 遍历Map:

    image

4.4 加强的IO

在Groovy中,文件访问要比Java简单的多,不管是普通文件还是xml文件。怎么使用呢?还是来查文档。

image

根据File的eachLine方法,我们可以写出如下遍历代码,可以看到,eachLine方法也是支持1个或2个参数的,这两个参数分别是什么意思,就需要我们学会读文档了,一味地从网上搜例子,多累啊,而且很难彻底掌握:

def file = new File("a.txt")
println "read file using two parameters"
file.eachLine { line, lineNo ->
   println "${lineNo} ${line}"
}

println "read file using one parameters"
file.eachLine { line ->
   println "${line}"
}

outputs:
read file using two parameters
1 hello
2 world
3 hello world

read file using one parameters
hello
world
hello world

除了eachLine,File还提供了很多Java所没有的方法,大家需要浏览下大概有哪些方法,然后需要用的时候再去查就行了,这就是学习Groovy的正道。

下面我们再来看看访问xml文件,也是比Java中简单多了。
Groovy访问xml有两个类:XmlParser和XmlSlurper,二者几乎一样,在性能上有细微的差别,如果大家感兴趣可以从文档上去了解细节,不过这对于本文不重要。

在下面的链接中找到XmlParser的API文档,参照例子即可编程

http://docs.groovy-lang.org/docs/latest/html/api/

假设我们有一个xml,attrs.xml,如下所示:

<resources>
<declare-styleable name="CircleView">

   <attr name="circle_color" format="color">#98ff02</attr>
   <attr name="circle_size" format="integer">100</attr>
   <attr name="circle_title" format="string">houyl</attr>
</declare-styleable>

</resources>

那么如何遍历它呢?

def xml = new XmlParser().parse(new File("attrs.xml"))
// 访问declare-styleable节点的name属性
println xml['declare-styleable'].@name[0]

// 访问declare-styleable的第三个子节点的内容
println xml['declare-styleable'].attr[2].text()


outputs:
CircleView
houyl

更多的细节都可以从我发的那个链接中查到,大家有需要查文档即可。

5. for循环

Groovy支持Java的for(int i=0;i<N;i++)和for(int i :array)形式的循环语句,另外还支持for in loop形式,支持遍历范围、列表、Map、数组和字符串等多种类型。

//遍历范围
def x = 0
for ( i in 0..3 ) {
    x += i
}
assert x == 6
//遍历列表
def x = 0
for ( i in [0, 1, 2, 3] ) {
    x += i
}
assert x == 6
//遍历Map中的值
def map = ['a':1, 'b':2, 'c':3]
x = 0
for ( v in map.values() ) {
    x += v
}
assert x == 6

6. Groovy的其他特性

除了本文中已经分析的特性外,Groovy还有其他特性。

6.1 Class是一等公民

在Groovy中,所有的Class类型,都可以省略.class,比如:

func(File.class)
func(File)

def func(Class clazz) {
}
6.2 Getter和Setter

在Groovy中,Getter/Setter和属性是默认关联的,比如:

class Book {
   private String name
   String getName() { return name }
   void setName(String name) { this.name = name }
}

class Book {
   String name
}

上述两个类完全一致,只有有属性就有Getter/Setter;同理,只要有Getter/Setter,那么它就有隐含属性。

6.3 with操作符

在Groovy中,当对同一个对象进行操作时,可以使用with,比如:

Book bk = new Book()
bk.id = 1
bk.name = "android art"
bk.press = "china press"

可以简写为:
Book bk = new Book() 
bk.with {
   id = 1
   name = "android art"
   press = "china press"
}


6.4 判断是否为真可以更简洁
if (name != null && name.length > 0) {}

可以替换为:
if (name) {}
6.5 简洁的三元表达式

在Groovy中,三元表达式可以更加简洁,比如:

def result = name != null ? name : "Unknown"

// 省略了name
def result = name ?: "Unknown"
6.6 简洁的非空判断

在Groovy中,非空判断可以用?表达式,比如:

if (order != null) {
   if (order.getCustomer() != null) {
       if (order.getCustomer().getAddress() != null) {
       System.out.println(order.getCustomer().getAddress());
       }
   }
}

可以简写为:
println order?.customer?.address

6.7 使用断言

在Groovy中,可以使用assert来设置断言,当断言的条件为false时,程序将会抛出异常:

def check(String name) {
   // name non-null and non-empty according to Groovy Truth
   assert name
   // safe navigation + Groovy Truth to check
   assert name?.size() > 3
}

6.8 switch方法

在Groovy中,switch方法变得更加灵活,可以同时支持更多的参数类型:

def x = 1.23
def result = ""
switch (x) {
   case "foo": result = "found foo"
   // lets fall through
   case "bar": result += "bar"
   case [4, 5, 6, 'inList']: result = "list"
   break
   case 12..30: result = "range"
   break
   case Integer: result = "integer"
   break
   case Number: result = "number"
   break
   case { it > 3 }: result = "number > 3"
   break
   default: result = "default"
}
assert result == "number"

6.9 ==和equal

在Groovy中,==相当于Java的equals,,如果需要比较两个对象是否是同一个,需要使用.is()。

Object a = new Object()
Object b = a.clone()

assert a == b
assert !a.is(b)

7. 编译、运行Groovy

配置好gradle的环境变量之后,然后就可以直接编译运行Groovy写的gradle文件了
在当面目录下创建build.gradle文件,在里面创建一个task,然后在task中编写Groovy代码即可,如下所示:

task(houyl).doLast {
   println "start execute houyl"
   haveFun()
}

def haveFun() {
   println "have fun!"
   System.out.println("have fun!");
   1
   def file1 = new File("a.txt")
   def file2 = new File("a.txt")
   assert file1 == file2
   assert !file1.is(file2)
}

class Book {
   private String name
   String getName() { return name }
   void setName(String name) { this.name = name }
}

只需要在haveFun方法中编写Groovy代码即可,如下命令即可运行:

gradle houyl
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 前言 由于项目需要用到 Groovy 语言,这两天对其进行了粗略的学习,本文是对学习做的一个简单总结,主要内容参考...
    简单的土豆阅读 188,169评论 12 202
  • 最近在学习 Android 中 Gradle 相关的知识,如果想学好 Gradle,必要的 Groovy 基础是不...
    lijiankun24阅读 4,460评论 4 15
  • Groovy :是一种动态语言。 1:这种语言比较有特点,它和 Java 一样,也运行于 Java 虚拟机中。简单...
    PeytonWu阅读 1,532评论 0 1
  • 在 Android Studio 构建的项目中,基于 Gradle 进行项目的构建,同时使用 Android DS...
    Ant_way阅读 7,312评论 0 16
  • 中午出来发快递,到了快递站却发现关门了,隔壁商铺热情的告诉我:工作人员回家吃午饭了,一会儿就回来。想想太阳这么毒,...
    玥灵儿阅读 859评论 14 16