书接上文,我们继续讲解Groovy的基础语法部分
- 逻辑条件
在Groovy中的逻辑和Java中的一样,大致分为3类:- 顺序逻辑-单步往下执行
- 条件逻辑-if/else switch/case
- 循环逻辑-while循环、for循环
重点讲述的是switch/case逻辑和for循环
part1: switch/case
def x=1.23
def result
switch(x){
case 'foo':
result='found foo'
break
case 'bar':
result='bar'
break
case [4,5,6,'inlist']://List 由[]定义,其元素可以是任何对象
result='list'
break
case 12..30://范围
result='range'
break
case Integer:
result='integer'
break
case BigDecimal:
result='big decimal'
break
defalut
break
}
在java中switch/case只能传入int类型、char类型 、String类型、枚举类型,但是在groovy中的switch/case可能匹配到任何类型的数据,简单的说可以替换if/else
当然也可以改造上面的代码如下
def x=1.23
def result
switch(x.class){
...
defalut
break
可以通过x.class来判断数据类型,比如是否为Integer、Double类型的数据,相当于是java中的instance of的类型判断
part2: for循环
//对范围进行循环
def sum=0
for (i in 0..9){
sum+=i
}
println sum
sum=0
//对List的循环 groovy中的List的写法和Java中的数组写法类似,List 由[]定义,其元素可以是任何对象
for(i in [1,2,3,4,5,6,,8,9]){
sum+=i
}
println sum
sum=0
//对Map进行循环 java中需要通过获取迭代器后进行操作,但是在groovy中已经处理过可以省略该操作
for(i in ['lili':1,'luck':2,'xiaoming':3){
sum++i.value
}
println sum
所以相比Java而言,groovy中的逻辑控制看起来比Java中的要更强大,功能更丰富。
- 闭包(重点)
通过和Java语法的比较,接下来我们继续学习下闭包的知识。闭包是groovy中的最强大的特性之一。
通过下面的几部分让我们更好的了解闭包这个特性- 闭包的基础
1.1 闭包概念
闭包就是一段代码块,使用起来和方法有点类似,但是又和方法有区别
1.2 闭包参数//闭包的定义 def clouser1={println 'Hello Groovy'} clouser1.call() //调用闭包 clouser1()//调用闭包
闭包和方法一样也可以和方法一样添加参数,执行具体内容语句//闭包的参数使用 //单个参数 def clouser={String name ->println "Hello ${name}"} clouser.call('groovy') //调用闭包 clouser(‘peter’)//调用闭包 def myname='wangwu' clouser(myname)//调用闭包 //两个参数,多个参数的写法则为在箭头左侧使用逗号分割添加想要添加的参数 def clouser2={String name,int age ->println "Hello ${name},My age is ${age}"} clouser2(‘peter’,20)//调用闭包 //隐式参数 it def clouser3={String name, ->println "Hello ${it}"} clouser3(‘peter’)//调用闭包,同样可以输出Hello peter
- 闭包的基础
String name->println 'Hello Groovy'
以箭头为分割,箭头之前就是闭包的参数部分,箭头后面的就是闭包体内容,如遇到如下代码,则表示参数为空
->println 'Hello Groovy'
1.3 闭包返回值
Java中的方法有两种返回类型,一种是有返回值,一种是无返回值,Groovy的函数里,可以不使用return xxx 来设置 xxx 为函数返回值。如果不使用 return 语句的话,则函数里最后一句代码的执行结果被设置成返回值
def getSomething(){
"getSomething return value" //如果这是最后一行代码,则返回类型为String
1000 //如果这是最后一行代码,则返回类型为 Integer
}
print getSomething() //结果:1000
但是在groovy闭包中一定会有返回值,如果闭包体里面没有return语句的时候,返回的就是null
//闭包返回值
def clouser={String name ->println "Hello ${name}"}
def myname='wangwu'
def result=clouser(myname)//调用闭包
println result//结果为null
def clouser1={String name ->return "Hello ${name}"}
def result1=clouser1(myname)//调用闭包
println result1//结果为Hello wangwu
- 闭包使用
2-1. 结合基本类型简单使用
//求指定number的阶乘
//方法一 :upto
int fab(int number){
int result=1
//1是从1开始,到number,1属于Integer类型,所以可以直接调用
1.upto(number,{num->result*=num})
return result
}
//方法二 :downto
int fab2(int number){
int result=1
//grovvy中闭包可以不放在括号内,可以直接放在括号外.像下面这个写法
number.downto(1){num->result*=num}
return result
}
//方法三 :times累加操作
int sum(int number){
int result
//times方法的参数也是闭包,闭包写在括号外是groovy中很常见的方式.times方法的实现循环始终是从0开始的
number.times {num->result +=num}
return result
}
int x=fab(5)
println(x) //输出结果:120
int y=fab2(5)
println(y) //输出结果:120
int z=sum(101)//因为times方法中是小于,所以参数+1
println(z) //输出结果:5050
//闭包传递参数类型及个数不知道时,需要查看源码方法中是如何调用的
Q:为什么没有使用循环,上面的方法都能实现阶乘的效果?
A:因为upto、downto、times里面的源码实现了for循环的操作,详见DefaultGroovyMethods源码类中的解析
public static void upto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) {
int self1 = self.intValue();
int to1 = to.intValue();
if (self1 > to1) {
throw new GroovyRuntimeException("The argument (" + to + ") to upto() cannot be less than the value (" + self + ") it's called on.");
} else {
for(int i = self1; i <= to1; ++i) {
closure.call(i);
}
}
}
public static void downto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) {
int self1 = self.intValue();
int to1 = to.intValue();
if (self1 < to1) {
throw new GroovyRuntimeException("The argument (" + to + ") to downto() cannot be greater than the value (" + self + ") it's called on.");
} else {
for(int i = self1; i >= to1; --i) {
closure.call(i);
}
}
}
//times中的循环是i < size,所以需要+1
public static void times(Number self, @ClosureParams(value = SimpleType.class,options = {"int"}) Closure closure) {
int i = 0;
for(int size = self.intValue(); i < size; ++i) {
closure.call(i);
if (closure.getDirective() == 1) {
break;
}
}
}
2-2. 闭包与String结合使用(结合源码进行学习)
String str='the 2 and 3 is 5'
//each遍历
str.each {
String temp->print temp.multiply(2)
}
//输出结果:tthhee 22 aanndd 33 iiss 55
each方法的返回值就是返回调用者的本身
print str.each {
// String temp->print temp.multiply(2)
}
//输出结果:the 2 and 3 is 5
//find来查找符合条件的第一个直接输出
print str.find{
String s->s.isNumber()
}
// 输出结果:2
//findAll来查找所有,添加符合条件的内容
def list=str.findAll{
String s->s.isNumber()
}
print list.toListString() // 输出结果:[2, 3, 5]
//字符串是否满足某种条件,查找到一个后返回true,否则是false
def result=str.any {
String s->s.isNumber()
}
print result //输出结果:true
//字符串是否满足某种条件,查找到所有的都满足后返回true,否则是false
def result=str.every {
String s->s.isNumber()
}
print result //输出结果:false
//collect:将字符串转换成List的结果
def collList=str.collect {
it.toUpperCase()
}
print collList.toListString() //输出结果:[T, H, E, , 2, , A, N, D, , 3, , I, S, , 5]
2-3. 闭包与数据结构的使用(在后面的数据结构的时候再进行学习)
2-4. 闭包与文件的使用(在后面学习文件的时候再进行学习)
- 闭包进阶知识
3-1:闭包强大的核心-关键字变量(this、owner、delegate)
首先看一段代码
def scriptClouser={
println 'script this:'+this
println 'script owner:'+owner
println 'script delegate:'+delegate
}
scriptClouser.call()
输出的结果
script this:grammer@2a54a73f
script owner:grammer@2a54a73f
script delegate:grammer@2a54a73f
Q:嗯?从上面的代码看,这三个输出的结果不是都是一个东西吗?区别在哪里?
A:答案如下
this:在java中的表明当前类的方法或者是变量,groovy中也是如此,定标闭包定义处的类,实例或者是类本身
owner:代码闭包定义处的类或者是对象,也就是说如果闭包中嵌套了闭包,那个owner表示的就是闭包内部的对象,而不再是当前类
delegate:任意一个第三方对象,默认指向了owner的对象
代码验证下:
class Person{
//static 指向了Person
def static classClouser={
println 'classClouser this:'+this //Person
println 'classClouser owner:'+owner //classClouser
println 'classClouser delegate:'+delegate //classClouser
}
def say(){
def methodClouser={
println 'classClouser this:'+this
println 'classClouser owner:'+owner
println 'classClouser delegate:'+delegate
}
methodClouser.call()
}
}
//闭包中定义闭包
def nestClouser={
def innerClouser={
println 'classClouser this:'+this
println 'classClouser owner:'+owner
println 'classClouser delegate:'+delegate
}
innerClouser.delegate=p //修改默认的delegate,此时owner和delagate就不一致了
innerClouser.call()
}
nestClouser.call()
3-2 委托策略
//闭包委托策略
class Student {
String name
def pretty = { "My name is ${name}" }
String toString() { pretty.call() }
}
class Teacher{
String name
}
def stu=new Student(name:'Sarash')
def tea=new Teacher(name:'Qroovy')
println stu.toString() //结果:My name is Sarash
如果此时我们需要获取到Teacher类中的属性,那么要怎么办?可以将代码更改如下:
class Student {
String name
def pretty = { "My name is ${name}" }
String toString() { pretty.call() }
}
class Teacher{
String name
}
def stu=new Student(name:'Sarash')
def tea=new Teacher(name:'Qroovy')
stu.pretty.delegate=tea//修改委托
stu.pretty.resolveStrategy=Closure.DELEGATE_FIRST//更改委托策略方式
println stu.toString() 结果:My name is Qroovy
在源码中发现Closure的常见的委托策略有下面四个值
public static final int OWNER_FIRST = 0;
public static final int DELEGATE_FIRST = 1;
public static final int OWNER_ONLY = 2;
public static final int DELEGATE_ONLY = 3;
从源码中可知,默认的委托策略就是OWNER_FIRST,假如此时代码改变成如下的形式又会是什么结果呢?
//闭包委托策略
class Student {
String name
def pretty = { "My name is ${name}" }
String toString() { pretty.call() }
}
class Teacher{
String name
}
def stu=new Student(name:'Sarash')
def tea=new Teacher(name:'Qroovy')
println stu.toString() //结果:My name is Sarash
如果此时我们需要获取到Teacher类中的属性,那么要怎么办?可以将代码更改如下:
class Student {
String name
def pretty = { "My name is ${name}" }
String toString() { pretty.call() }
}
class Teacher{
String name
}
def stu=new Student(name:'Sarash')
def tea=new Teacher(name:'Qroovy')
stu.pretty.delegate=tea//修改委托
stu.pretty.resolveStrategy=Closure.DELEGATE_ONLY//更改委托策略方式
println stu.toString()
猜想下应该是报错,因为在策略中我们并没有发现name1这个属性,现在验证下结果
Caught: groovy.lang.MissingPropertyException: No such property: name for class: Teacher
Possible solutions: name1
groovy.lang.MissingPropertyException: No such property: name for class: Teacher
Possible solutions: name1
at Student$_closure1.doCall(grammer.groovy:83)
at Student$_closure1.doCall(grammer.groovy)
at Student.toString(grammer.groovy:85)
at Student$toString.call(Unknown Source)
at grammer.run(grammer.groovy:98)
果然,报错也是提示name1这个属性不在策略中,通过上面代码的学习,我们也算是对闭包有了一个了解了,关于这个委托策略,我觉得在普通的代码中可能用的少,但是涉及到框架的时候就用的比较多了。
小伙伴们可以通过自己修改上述代码进行你们的猜想和验证。