Gradle从入门到实战 - Groovy基础

前言

Android方向的第一期文章,会专注于Gradle系列,名字叫做『 Gradle从入门到实战』,计划有如下几个课程:

  • Groovy基础
  • 全面理解Gradle
  • 如何创建Gradle插件
  • 分析Android的build tools插件
  • 实战,从0到1完成一款Gradle插件

本篇文章讲解Groovy基础。为什么是Groovy基础呢,因为玩转Gradle并不需要学习Groovy的全部细节。Groovy是一门jvm语言,功能比较强大,细节也很多,全部学习的话比较耗时,对我们来说收益较小。

为什么是Gradle?

Gradle是目前Android主流的构建工具,不管你是通过命令行还是通过AndroidStudio来build,最终都是通过Gradle来实现的。所以学习Gradle非常重要。

目前国内对Android领域的探索已经越来越深,不少技术领域如插件化、热修复、构建系统等都对Gradle有迫切的需求,不懂Gradle将无法完成上述事情。所以Gradle必须要学习。

如何学习Gradle?

大部分人对Gradle表示一脸懵逼,每当遇到一个问题的时候都需要从网上去查,这是一个误区。

Gradle不单单是一个配置脚本,它的背后是几门语言,如果硬让我说,我认为是三门语言。

  • Groovy Language
  • Gradle DSL
  • Android DSL

DSL的全称是Domain Specific Language,即领域特定语言,或者直接翻译成“特定领域的语言”,算了,再直接点,其实就是这个语言不通用,只能用于特定的某个领域,俗称“小语言”。因此DSL也是语言。

在你不懂这三门语言的情况下,你很难达到精通Gradle的程度。这个时候从网上搜索,或者自己记忆的一些配置,其实对你来说是很大的负担。但是把它们当做语言来学习,则不需要记忆这些配置,因为语言都是有文档的,我们只需要学语法然后查文档即可,没错,这就是学习方法,这就是正道。

你需要做什么呢?跟着我学习就行啦!下面步入正题,让我们来开始学习Groovy的基本语法。

Groovy和Java的关系

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

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

Groovy的变量和方法声明

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

def a = 1;
def b = "hello world";
def int c = 1;

def hello() {
   println ("hello world");
   return 1;
}

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

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

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

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 hello(msg) {
   println msg
   return 1 // 这个return不能省略
   println "done"
}

总结

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

Groovy的数据类型

在Groovy中,数据类型有:

  • Java中的基本数据类型
  • Java中的对象
  • Closure(闭包)
  • 加强的List、Map等集合类型
  • 加强的File、Stream等IO类型

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

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

1. String

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

def a = 1
def b = "hello"
def c = "a=${a}, b=${b}"
println c

outputs:
a=1, b=hello

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

下面会结合具体的例子来说明如何查文档。

3. List和Map

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

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中添加新元素的意思,这一点从文档当也能查到。

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

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的方式,通过查看文档,发现它有如下两个方法,看起来和遍历有关:

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

通过文档可以发现,这个闭包的参数还是不确定的,如果我们传递的闭包是一个参数,那么它就把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]

另外一个eachWithIndex方法教给大家练习,自己查文档,然后尝试用这个方法去遍历。

试想一下,如果你不知道查文档,你又怎么知道each方法如何使用呢?光靠从网上搜,API文档中那么多接口,搜的过来吗?记得住吗?

4. 加强的IO

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

根据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 欢迎
2 关注
3 玉刚说

read file using one parameters
欢迎
关注
玉刚说

除了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">renyugang</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
renyugang

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

Groovy的其他特性

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

  • Class是一等公民

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

func(File.class)
func(File)

def func(Class clazz) {
}
  • 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,那么它就有隐含属性。

  • 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"
}
  • 判断是否为真

在Groovy中,判断是否为真可以更简洁:

if (name != null && name.length > 0) {}

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

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

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

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

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

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

可以简写为:
println order?.customer?.address
  • 使用断言

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

def check(String name) {
   // name non-null and non-empty according to Gro    ovy Truth
   assert name
   // safe navigation + Groovy Truth to check
   assert name?.size() > 3
}
  • 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"
  • ==和equals

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

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

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

本小节参考了如下文章,十分感谢原作者的付出:

1. http://www.jianshu.com/p/ba55dc163dfd

编译、运行Groovy

可以安装Groovy sdk来编译和运行。但是我并不想搞那么麻烦,毕竟我们的最终目的只是学习Gradle。

推荐大家通过这种方式来编译和运行Groovy。

在当面目录下创建build.gradle文件,在里面创建一个task,然后在task中编写Groovy代码即可,如下所示:

task(yugangshuo).doLast {
   println "start execute yuangshuo"
   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 yugangshuo

 

本公众号聚焦于『Android开发前沿、AI技术等、职业发展、生活感悟、妹子图』,欢迎大家关注玉刚说:

 

相关推荐
欢迎进入 groovy 世界。 也许你已经在某些博客和邮件列表中听说过 groovy,已经在这里或者哪里看到了 groovy 的片段报道,大概你的同事已经告诉你用 java 写的一页代码在 grovvy 中只需要短短的几行 就可以完成相同的工作,也许你仅仅因为这本书的名字比较好记而翻阅这本书,为什么你应 该学习 groovy?你期望的回报是什么? Groovy 将让你迅速的获得成功,groovy 比用 java 写代码更加简单,更易进行自动化重 复的任务,还可以作为日常工作用来编写特别脚本,groovy 的代码阅读起来更加自然易懂, 当然更重要的是,groovy 用起来更加有趣。 学习 groovy 是一项明智的投资。Groovy 给给 java 平台带来高级语言强大的特性,如闭 包、动态类型和元对象协议,你现有的 java 知识在 Groovy 中仍然有效,而不会过时。Groovy 建立在你现有的 java 经验和熟悉程度之上,这样你可以在适当的时候进行选择,或者混合 使用 java 和 groovy。 如果对在 Ruby 上实现一个 web 应用不会感到惊奇的,Python 变戏法似的容器,Perl 人 员通过少数的键盘输入来进行服务器管理,或者 Lisp 领袖利用极少的代码改变转向他们整 个代码库,那么想想他们使用的语言的语言特性。Groovy 的目标是在 java 平台有提供类似 功能的语言,尽量保留 java 对象模型和对 java 编程人员保持透明。 我们坚信学习一门程序语言的唯一途径是:动手尝试它,我们介绍编译程序、解释程序 和处理程序处理脚本时各种各样的变化;列出了在广泛使用的 IDE 上使用的各种插件和找 到 groovy 最新信息的地方。 在本章的最后你将对 groovy 的使用有一个基本的认识。 衷心希望你在用 groovy 编程时和使用本书做指定参考时有一个愉快的时光。
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页