本文概述
前言
所以为什么学Groovy呢?完全是因为Gradle了,本人并不喜欢Gradle这种构建脚本,因为它使用了另一种语言:Groovy。虽然Groovy可以使用Java的方式编程,但它还是是新语言,多数情况都是使用它的新特性的。而且它是弱语言和动态语言,感觉诸多不方便,所以我刚开始使用Gradle构建的时候,压根不会写,不知道是啥东西,不管三七二十一,配置全部复制一通。
但是因为不会写Gradle脚本,开发还是很多不便,想下编程的日子还有若干年呢,不如学下也好。而构建工具是写所有项目都是几乎要学的,例如C/C++的Make,Java的另一个Maven,要想项目写的顺利,需要在构建工具上花一些精力。
为了解决编写Gradle脚本的问题,用了几天时间学了一下Groovy,本文是一个简单总结,足够应付Gradle脚本了。再有不认识的可以即学即用,而且它兼容Java,实在不知道就用Java写吧。
构建的第一个问题:构建工具要做什么?
我想大部分程序员入门是不重视构建工具的,可能有些机会使用命令行编程,但随后就开始进入IDE编程了,所以这造成后来使用不同的配置或构建脚本会觉得诸多不便,比如我就是。
但是这个问题我写了很多文章都说过了,这里只是结合Gradle和Groovy重复说一次。首先,任何编程基本都是:编写代码,将代码编译成字节码或直接运行。例如Java就需要先将一个Java文件编译成.class字节码文件,然后才能运行。
这里的问题是,如果你只是写一个简单的HelloWorld,那就还好。如果你在开发一个小型的工具,那么这时候就会编写很多个Java文件,这样我们就要手动输入很多次重复而相似的命令进行编译和运行。
这样重复的工作如何简单化呢?这时候构建工具就来了,构建工具基本上就是一个程序,这个程序帮助我们编译或构建整个项目,很多重复的工作就不需要手动处理了。IDE就是嵌入了构建工具和编辑器,另外还有调试器,其它IDE自带的功能都是次要的。
例如在Maven中,我们可以使用mvn compile来编译当前项目,但是目前的构建工具并不仅仅只有编译这个功能,例如还有打包、部署等功能。
构建脚本的工作是什么?
虽然你可能会用构建脚本辅助项目构建了,但是这还不行,随便配置一番,这似乎对项目开发也没多大作用。这还是要记得项目构建的最初需求或动机,它至少要帮我们实现:项目的编译和打包,输出一个最终的产品供我们发布和使用。
下面是构建工具的主要工作:
- 配置仓库:指定包的来源,有可能构建工具已经有默认的仓库地址了,有时也需要手动再配置。但是有的构建工具是不带包管理器的,也就是不需要配置仓库。
- 配置依赖:如果当前构建工具需要依赖第三方库,那么我们可以配置一些用到的依赖,这个一般比较简单,到中心仓库搜索并复制配置即可。
- 构建生命周期:一般构建工具有一个构建生命周期,因为我们不总是编译并生成最终产品,有时我们只是想编译一下,或只是想运行全部的测试,例如常见的清理构建生成文件、编译项目、测试项目、打包项目、发布项目。
- 构建配置和策略:根据最终的target进行的配置,例如指定构建平台,特定的系统:针对Linux?32位还是64位?根据构建生命周期进行的配置:清理文件策略,编译策略或逻辑,测试测量,打包策略,发布地址配置等等。
其中生命周期是比较重要的,使用任何一个构建工具,务必要了解其构建生命周期。而构建策略则是重点,例如Android的DEX文件方法数超过65536,那你就要手动解决了。
而构建脚本就是要完成以上相关的任务,或者说,构建脚本的配置工具就是这4个了。
Groovy基本特色
Groovy是兼容Java的,支持强类型,所以你完全可以使用Java进行编程,但常用的是弱类型、动态编程,但不要忘记,如果使用动态编程行不通,大可考虑Java。
Groovy定义变量使用def,类似JS中的var,或一些语言中的auto:
def num = 90;
def str = "Groovy"
println num
println str
上面你可以看到Groovy调用函数是可以不用括号的,这是常用的方式,如果有多个参数,使用逗号分隔即可。另外,语句后面可以不用分号。函数的返回值可以不用return语句,groovy使用函数的最后一个表达式的值作为返回值。
下面是函数的一般使用形式:
def f() {
println 'function in groovy'
}
def f1(def str) {
println str
}
def f2(def a, def b) {
println a + b
}
f()
f1 'Hello Groovy'
f2 3, 4
Groovy中的字符串类似PHP中的字符串,最基本的可以使用单引号,双引号也是基本字符串,但是可以在字符串中引用外部变量或调用函数,三引号的字符串可以换行。
Groovy中的字符串相当于一个字符数组,所以你可以把它当做一个字符列表进行CRUD操作。
def str1 = 'sample string'
def a = 90
def str2 = "number: $a"
def str3 = '''
Groovy Console
'''
println str1
println str2
println str3
def f() {
'Android build.gradle'
}
println "Groovy for: ${f()}"
Groovy支持闭包,现在很多高级语言都支持闭包,例如JS,它的用法很简单,对于它的原理就不再讨论了,只需要看它怎么用就行了。
Closure c1 = { a, b, c ->
println a + b + c
}
c1(2, 3, 4)
def c2 = { i, j, k ->
i + j + k
}
c2 3, 4, 5
闭包是groovy是最重要的一个特色,特别在gradle中常用到闭包,例如Android gradle常见的配置:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
}
}
其中buildscript是一个函数,后面{}是一个闭包,意思是buildscript的参数是一个闭包。下面我们来实现类似的功能:
def f(c) {
c()
}
f {
println 'groovy'
println 'java'
println 'android'
println 'gradle'
}
以上就是groovy的主要特色,其它不再详细讨论,最好你有一些Java、Python、Ruby或JS的编程经验,和它们是类似的。
Groovy API文档
更多的Groovy的类或接口可以参考Groovy API在线文档:http://www.groovy-lang.org/api.html。因为是使用Groovy编程,所以尽量还是使用Groovy的特色,而不是使用原生的Java,如果不太了解可以查看Groovy API的参考文档。
Groovy语法糖
使用Map作为函数的参数:
def printMap(map) {
println map
}
printMap([1: "11", 2: "22", 3: "33", 4: "44"])
printMap 3: "POM", 4: "Gradle", 5: "Git"
快速创建变量,和变量的值交换:
def (a, b, c) = [[1, 9, 2], 2, 4];
(a, b, c) = [b, c, a]
println a
println b
println c
函数科里化:
def cl1 = {int a, b, c ->
a + b + c
}
def cl1Curry1 = cl1.curry(1)
shell调用:
println "ls -l".execute().text
总结
上面就是Groovy的主要内容了,如果你有Java基础,那么Groovy其实非常简单,不同的是Groovy的新特性、新的API和一些语法糖,其中最重要的是闭包。
但是不会深入Groovy的开发,能用就行,因为我们最多是使用Groovy作为简单的脚本配置,项目开发还是使用普通的语言,如Java或C/C++。而Groovy是DSL语言,特定领域语言,意思是它只针对特定领域的,而像Java这样的语言,则可以适应普遍的应用开发。
好了,先到这里了,下一篇再详细讨论Gradle的用法和使用。