Groovy程序设计-【第一部分Groovy起步】-02-面向Java开发者的Groovy

前言:

知识点记录来源于【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.布尔求值

groovy的布尔求值和java的不同,根据上下文,groovy会自动把表达式计算为布尔值,先看一下例子,如下:

// java代码
String str = "hello";
int value = 4;
if (str){} // 错误语法
if (value){} // 错误语法

java要求if中的表达式必须是一个布尔表达式,例如 if(obj != null) 这种,但是groovy可不是,它会尝试判断。

如果在需要布尔表达式的地方发了一个对象引用,例如 if 中,groovy会检查这个引用是否为null,null视为false,非null视为true,如下:

def str = "groovy"
if (str) { println "hi, " + str }
// 输出结果
hi, groovy

如上,groovy将str视为表达式计算布尔值。

其实上面说的根据引用对象是否为null判断布尔值也不是对的,因为如果对象不为null,表达式的结果还和对象的类型有关,例如集合List,只有集合不为null,且至少有一个元素,才会认为true,示例代码如下:

def list = [];
println "集合, 空判断: " + (list ? "true" : "false")

list = null;
println "集合, null判断: " + (list ? "true" : "false")

list = [1];
println "集合, 有值判断: " + (list ? "true" : "false")

输出结果如下:

集合, 空判断: false
集合, null判断: false
集合, 有值判断: true

不仅仅集合,其他一些类型也是不仅判断null,groovy如何判断的呢,如下图:
在这里插入图片描述

6.操作符重载

groovy支持操作符重载,就是每个操作都会映射到一个标准的方法。下面演示一个示例:(截图)
在这里插入图片描述通过 ++ 操作符实现了字符a到c的循环打印,该操作符映射的是String类的next()方法,还可以进一步使用range的简介循环:
在这里插入图片描述集合也有操作符,例如 << 操作符表示向集合中添加元素,相当于leftShift()方法。
在这里插入图片描述
输出结果
在这里插入图片描述

7.陷阱

groovy确实有很多不错的功能,但是同时也存在一些“陷阱”。

7.1.groovy的==等价于java的equals()

java的==和equals()本来就已经够混乱的了,groovy又再一次加剧了“悲剧”的发生。

groovy中,==操作符映射到了java的equals()方法,那么如果我们想要对比对象的引用地址是否想等(就是java中的 ==)怎么办呢,必须使用groovy中的 is()方法,如下:

 def str1 = "hello"
 def str2 = str1
 def str3 = new String("hello")
 def str4 = "Hello"

 // true
 println "str1 == str2: ${str1 == str2}"
 // true
 println "str1 == str3: ${str1 == str3}"
 // false
 println "str1 == str4: ${str1 == str4}"
 // true
 println "str1.is(str2): ${str1.is(str2)}"
 // false
 println "str1.is(str3): ${str1.is(str3)}"
 // false
 println "str1.is(str4): ${str1.is(str4)}"

实际上groovy的==并不总是映射到java的equals()方法,只有该类没有实现Comparable的时候才成立,否则groovy的==会映射到该类的compareTo()方法。
在这里插入图片描述通过输出发现,实现了Comparable接口的,==映射到了compareTo()方法,而不是equals()方法,所以,在比较对象的时候,首先确定自己想要对比的是值和引用地址,然后再确定是不是使用了正确的操作符(==还是is方法)

7.2.编译时类型检查默认关闭

groovy类型是可选的,然而groovy编译时大部分情况下不会检查完整的类型,而是在运行时遇到类型执行强制类型转换,例如:
在这里插入图片描述
这段代码可以正常编译,但是运行时就会报错,因为groovy不会检查,运行时候 hello 强制转换为int类型的时候就报错了,所以groovy把这工作留给了运行时处理。

所以groovy中的 x = y,实际上就是 x = (ClassOfX)y。类似的,如果调用了一个不存在的方法,编译也是通过的,运行时就会报错:
在这里插入图片描述为什么groovy这么做,后续会说明,其实这反而对groovy来说是一个有点哟!

7.3.新的关键字

groovy的 in ,def 都对于java来说是新的关键字,需要注意。

同时注意 it,这对groovy来说也是一个特殊的关键字。

7.4.创建基本类型的数组

groovy创建一个int数组,如下:

int[] size = [1,2,3]

定义了一个数组,如果去掉了 int[],groovy就会认为定义了一个集合:

def size = [1,2,3]

这样就是一个集合了,如果还想这么定义一个数组,就需要做出一点改变,如下:

def size = [1,2,3] as int[]
  • 12
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值