前言:
知识点记录来源于【Groovy程序设计】一书中,本文仅作知识点记录供日后使用查询,不做教程使用。
groovy支持java语法,并且保留了java的语义,所以我们可以随心所欲的混用两种语言。
1.从Java到Groovy
先看一个简单的java代码的for循环,使用groovyConsole运行一下,如下:
可以看出简单的循环,“无用”的java代码可真多,实际上在groovy中,去掉每一行的分号也是被允许的。
注意:这里先说明,groovy代码编写的时候不必导入所有的常用类和包,例如,使用Calendar使用可以毫无困难的引入,同时groovy自动导入下列包:java.lang、java.util、java.io和java.net 等等。还会导入java.math.BigDecimal和java.math.BigInteger两个类等,此外,还导入了groovy.lang和groovy.util这些Groovy包。
同时,在groovy中,去掉类和方法的定义也是可以的,上面的java循环使用groovy改造后如下:
for (int i = 0; i < 3; i++) {
// 注意,代码最后没有分号了哦
System.out.print("ho ")
}
System.out.println("Merry Groovy!!!")
甚至可以更进一步,groovy理解 println()方法,因为该方法添加到了java.lang.Object中了,同时groovy还有一个使用Range对象的更为轻量级的for循环,而且groovy对括号也很“不在意”,因此最终循环代码可以如下:
for(i in 0..2) {
print 'ho '
}
println 'Merry Groovy!'
比java代码更简单明了!
1.1.实现循环的方法
上面用到了for循环以及改造为range 0…2 的方法,但是groovy还提供了更多更优雅的迭代方式。
比如 upto(),这是groovy在java.lang.Integer类中添加的一个便于使用的实例方法,可用于迭代,如下:
在 0 上调用了 upto(),这里的0就是Integer的是一个实例,输出现实的是所选范围内的每个值,0 1 2。
代码中的 $it 代表的是,上下文中进行循环时的索引值,后续会具体说明,这里只需要知道即可。it前面的 $ 表示让print()打印该变量的值,而不是it这两个字符。
使用 uptp()方法时,可以设置范围的上限和下限,如果范围从0开始,可以使用times(),例如上面的0.uptp(2),可以改为如下:
3.times {
print "$it "
}
结果会和 0.upto(2)相同的结果,0 1 2
要在循环时跳过一些值,可以使用 step()方法, 如下:
最后,我们再回顾从Java到Groovy中的for range循环的groovy示例,是不是也可以写成下面这样:
3.times {print "ho "}
println "Merry Groovy!"
1.2.代码中执行命令
String扩展了execute()方法,当执行的时候,groovy创建了一个扩展了java.lang.Process的类的实例,执行实例如下:
print "svn help".execute().text
调用text时,实际是在调用groovy在类Process类上添加的getText()方法,功能就是将该进程的标准输出到一个String对象中。除了svn help,还可以执行如下:
print "groovy -v".execute().text
print "ls -l".execute().text
注意:如果你是win系统,执行这些命令是不行的(linux和unix可以),明确的说需要调用cmd命令(语法也不同,例如ls需要改成dir),例如:
print "cmd /c groovy -v".execute().text
1.3.操作符?.
经常检查对象引用是否为null?groovy可以使用?.进行判断,如下:
def foo(str){
// if (str != null) {str.reverse()}
str?.reverse()
}
println foo('evil')
println foo(null)
操作符 ?. 只有在引用不为null的时候才会调用执行的方法或属性,运行结果如下:
live
null
1.4.异常处理
java开发中,必须强制处理编译异常,例如Thread的sleep()方法,必须处理InterruptedException异常,File的处理必须处理FileNotFoundExcetion,如下:
但是groovy不需要,groovy中如果不想处理异常,groovy会默认自动传递给调用者由调用者进行处理,如下:
没有任何异常捕获处理和抛出,由调用者处理异常,如下:
如上,捕获指定的异常使用catch即可,但是如果想要捕获所有的异常而不是某一个,可以如下:
使用catch(ex),ex前面没有任何类型,这样就可以捕获所有的异常了,但是需要注意,ex不会捕获Exception之外的Error或Throwable,如果需要,使用 catch(Throwable throwable)
2.可选形参
groovy中的可选形参必须位于方法参数列表的末尾,定义可选形参,需要在形参列表上给它赋一个值,如下,方法log()中有一个可选的base形参,如果不提供实参,groovy认为它的默认值就是10:
def log(x, base=10){
...
}
// 调用log
println log(1024)
println log(1024, 10)
println log(1024, 2)
groovy还会把末尾的数组形参作为是可选的,这其实就相当于java中的可变参数,如下:
def task(name, String[] details){
println "$name - $detailds"
}
// 调用
task('Call')
task('Call', '123')
task('Call', '123', '456')
task('Call', '123', '456', '789')
// 输出结果
Call - []
Call - [123]
Call - [123, 456]
Call - [123, 456, 789]
从输出结果可以看出,groovy把末尾的参数(除了name参数之外的所有剩余参数)收集起来了赋值给数组。
3.使用多赋值
向方法传递参数获取方法的返回,如果希望方法返回多个结果,这很实用,groovy可以从方法返回的多个结果一次性赋值给多个变量,我们可以让方法返回一个数组,然后左侧用多个变量逗号分割,放在圆括号中接收即可。
其实这个类似于java中的Pair<left, right>的用法,但是java中的Pair需要自己get然后赋值,groovy不需要而且更简洁,如下:
// 空格分割参数, 返回数组
def splitname(fullname){ fullname.split(' ' )}
// 左侧两个变量接收
def (firstname, lastname) = splitname('James Bond')
// 打印结果
println "$firstname - $lastname"
结果输出:
James - Bond
可以发现,你都不用创建变量firstname和lastname,直接使用接受即可。
还可以使用该特性交换变量,不用创建中间变量过度了,如下:
def name1 = "test1"
def name2 = "test2"
println "name1:$name1, name2:$name2"
// 交换,注意上面已经定义了name1和name2,这里直接()即可,外面无需追加def再次定义
(name1, name2) = [name2, name1]
println "交换之后:"
println "name1:$name1, name2:$name2"
结果输出:
name1:test1, name2:test2
交换之后:
name1:test2, name2:test1
注意:如果左边变量个数 和 右侧数组的个数 不一致,groovy会这样处理,左侧的多余变量置为null,右侧的多余值被丢弃。
4.实现接口
在groovy中可以把一个映射或一个代码块转化为接口,因此可以快速直线带有多个方法的接口。这里使用线程Thread的执行举例,如下:
// 模拟java创建线程并执行
new Thread(() -> {
println("线程执行1");
}).run();
使用groovy:
new Thread(println("线程执行2") as Runnable).run()
看到了吗,groovy不需要Runabled的方法声明(java8开始出现了lambda),也不需要匿名内部类的实例,借助 as 操作符,相当于实现了Runabled接口。
上面是一个方法的实现,如果多个方法的接口中,只打算实现其中的某些方法而不是全部(只关心自己需要的方法),其实也很简单,只需要创建一个映射,以每个方法的名字作为键,方法对应的代码块作键值,同时用 冒号(:)分割方法名和代码块即可,如下(截图):
5.布尔求值
。。。进行中。。。休息,休息一下!!!