gradle学习-Groovy基础

Groovy基础

  • 字符串处理

每一门变成语言都会有字符串的处理,Java相对要稍微复杂一些,对程序员的开发限制比较多。相对而言,Groovy非常方便,比如字符串的运算、求值、正则等

在Groovy中分号不是必必需的。相信很多用Java的读者都习惯了每一行结束必需要有分号,但是Groovy没有这个强制规定。

1.单引号是单纯的字符串常量
2.双引号字符串常量里可以做许多运算操作,而单引号却不能

task printString << {
   def str1 = '单引号'
   def str2 = "双引号"
  println "单引号定义的字符串类型:"+str1.getClass().name
  println "双引号定义的字符串类型:"+str2.getClass().name

  def name = "张三"
  println '单引号的变量计算:${name}'
  println "单引号的变量计算:${name}"
}

运算结果:

Task :printString
单引号定义的字符串类型:java.lang.String 双引号定义的字符串类型:java.lang.String 单引号的变量计算:${name}
单引号的变量计算:张三

  • 集合
    在Java里,定义一个List,需要New一个实现了List接口的类,太繁琐了。在Groovy中则非常简单:
task printList << {
  def numList = [1, 2, 3, 4, 5, 6]
  println numList.getClass().name
}

Groovy提供下标索引的方式访问,就像数组一样,除此之外,还提供了负下标和范围索引。负下标索引代表从右边开始,-1代表从右侧第一个,-2代表从右侧第二个,以此类推;1..3这种是一个范围索引,中间用两个“.”分开,这个会经常遇到。

除了访问方便之外,Groovy还为List提供了非常方便的迭代操作,这就是each方法,该方法接受了一个闭包作为参数,可以访问List里的每个元素:

task printList << {
  def numList = [1, 2, 3, 4, 5, 6]
  println numList.getClass().name

  println "numList[1] = " + numList[1]//访问第二个元素
  println "numList[-1] = " + numList[-1]//访问最后一个元素
  println "numList[-2] = " + numList[-2]//访问倒数第二个元素
  println "numList[1..3] = " + numList[1..3]//访问第二个到第四个元素

  numList.each {
    print it
  }
}

it变量就是正在迭代的元素,这里有闭包的知识。我们可以先这么记住,后面会纤细讲解。

  • Map

map的用法和List很像,只不过它的值是一个K:V键值对。所以在Groovy中Map的定义也非常简单:

task printMap << {
  //Map的定义
  def map1 = ['width':1024,'height':768]
  println map1.getClass().name
  }

我们能看出Map的访问也非常灵活,采用map[key]或者map.key的方式都可以,这两种方式都能快速取出制定的key和value值,必用Java方便多了。
对于Map的迭代,当然也少不了each方法,只不过被迭代的元素是一个Map.Entry的实例。

task printMap << {
  //Map的定义
  def map1 = ['width':1024,'height':768]
  println map1.getClass().name

  //map的访问
  println map1['width']
  println map1.height

  //map的迭代
  map1.each {
    println "Key : Z ${it.key},Value:${it.value}"
  }

}

对于集合,Groovy还提供了许多诸如collect、find、findAll等便捷方法,有兴趣的读者可以找相关文档看看,这里就不一一讲了。

  • 方法

1. 括号是可以省略的
我们在Java中调用一个方法都是用invokeMethod(param1,param2),非常规范,Java就是这么中规中矩的语言。在Groovy中就要灵活得多,可以省略(),变成invokeMethod param1,param2这样是不是觉得非常简洁,这在DSL的时候非常有用,书写也非常方便:

task invokeMethod << {
  method(1,2)
  method 1,2
}

def method(int a,int b){
  println a+b
}

task printMethodReturn << {
  def add1 = method2 1,2
  def add2 = method2 5,3
  println "add1:${add1},add2:${add2}"
}

2. return是可以不写的
在Groovy中我们定义有返回值得方法时,return语句不是必需的。当没有return的时候,Groovy会把方法执行过程中的最后一句代码作为其返回值

task printMethodReturn << {
  def add1 = method2 1,2
  def add2 = method2 5,3
  println "add1:${add1},add2:${add2}"
}

def method2(int a,int b){
  if(a > b){
    a
  }else{
    b
  }
}

运行结果:

Task :printMethodReturn
add1:2,add2:5

3. 代码块是可以作为参数传递的
代码块是一段花括号包围的代码,其实就是后面要讲的闭包。Groovy是允许其作为参数传递的,但是结合我们上面讲的方法特性来用,最后的基于闭包的方法调用就会非常优雅、易懂、以集合的each方法为例,它接受的参数其实就是一个闭包:

task myTask << {

  //呆板的写法
  numList.each({ println it })

  //格式化以后,是不是更优雅一些?
  numList.each({
    println it
  })

  //Groovy规定,如果方法的最后一个参数是闭包,可以放到方法外面
  numList.each(){
    println it
  }

  //然后方法可以省略,就变成我们经常看到的样式
  numList.each {
    println it
  }

}
  • JavaBean

JavaBean是一个非常好的概念,你现在看到的组建化、插件化、配置集成都是基于JavaBean。在Java中为了访问和修改JavaBean的属性,我们不得不重复生成getter/setter方法,并且使用它们,太繁琐,这在Groovy中得到很大的改善:

task helloJavaBean << {
   Person p = new Person()

  println "名字是: ${p.name}"
  p.name = '张三'
  println "名字是:${p.name}"
  println "age:${p.age}"

}

class Person {
  private String name
  public int getAge(){
     12
  }
}

Task :helloJavaBean
名字是: null
名字是:张三
age:12

在没有给name属性赋值的时候输出null,赋值后输出的就是“张三”了。通过上面的例子,我们发现,在Groovy中可以非常容易地访问和修改JavaBean的属性值,而不用借助getter/setter方法,这是因为Groovy帮助我们搞定了一些功能。

  • 闭包

闭包是Groovy的一个非常重要的特性,可以说它是DSL的基础。闭包不是Groovy的首创,但是它支持这一重要的特性,这就是使得代码灵活、轻量、可复用,再也不用像java一样动不动就要用一个类了。虽然java后来有了匿名内部类,但是一样冗余不灵活。

1.初始闭包

task helloClosure << {
  //使用我们自定义的闭包
  MyEach {
    println it
  }
}


static def MyEach(closure){
  //模拟一个有10个元素的集合,开始迭代
  for(int i in 1..10){
    closure(i)
  }
}

在上面的例子中我们定义了一个方法MyEach,它只是一个参数,用于接收一个闭包(代码块)。那么这个闭包如何执行呢?很简单,跟一对括号就是执行了。

2.向闭包传递参数

当闭包有一个参数时,默认就是it;当有多个参数时就不能这样表示了,我们需要把参数一一列出

task helloParamsClosure << {
  eachMap {k,v ->
    println "${k} is ${v}"

  }

}

def eachMap(closure){
  def map1=["name":"张三","age":18]
  map1.each {
    closure(it.key,it.value)
  }
}

从这个例子中我们可以看出,我们为闭包传递了两个参数,一个是key,一个是value。此时我们就不能使用it了,必须要显式申明粗来,如例子中的k、v、-> 用于把闭包的参数和主体区分开来。

  • 委托闭包

Groovy闭包的强大之处在于它支持闭包方法的委托。Groovy的闭包有thisObject、owner、delegate三个属性,当你在闭包内调用时,由他们确定使用哪个对象来处理。默认情况下delegate和owner是相等的,但是delegate是可以被修改的,这个功能是非常强大的,Gradle中的闭包的很多功能都是通过修改delegate实现的:

task helloParamsClosure << {
  eachMap {k,v ->
    println "${k} is ${v}"

  }

}

def eachMap(closure){
  def map1=["name":"张三","age":18]
  map1.each {
    closure(it.key,it.value)
  }
}
task helloDelegate << {
  new Delegate().test {
    println "thisObject:${thisObject.getClass()}"
    println "owner:${owner.getClass()}"
    println "delegate:${delegate.getClass()}"
    method3()
    it.method3()
  }
}

def method3(){
  println "Context this:${this.getClass()} in root"
  println "method in root"
}

class Delegate {
  def method3(){
    println "Delegate this:${this.getClass()} in delegate"
    println "method in Delegate"
  }
  def test(Closure<Delegate> closure){
    closure(this)
  }
}

程序运行结果如下:

Task :helloDelegate
thisObject:class build_202knba1xpeza2oarchhbot3m
owner:class build_202knba1xpeza2oarchhbot3m_run_closure11 delegate:class build_202knba1xpeza2oarchhbot3m_run_closure11
Context this:class build_202knba1xpeza2oarchhbot3m in root
method in root
Delegate this:class Delegate in delegate
method in Delegate

通过上面的例子我们发现,thisObject的优先级最高,默认情况下,优先使用thisObject来处理闭包中调用的方法,如果有则先执行。从输出中我们可以看到,这个thisObject其实就是这个构建脚本的上下文,它和脚本中的this对象是相等的。

从例子中也证明了delegate和owner是相等的,它们两个的优先级是:owner要比delegate高,所以闭包内方法的处理顺序是:thisObject>owner>delegate

在DSL中,比如Gradle,我们一般会指定delegate为当前it,这样我们在闭包内就可以对it进行配置,或者调用其方法:

task configClosure << {
  person {
    personName = "张三"
    personAge = 20
    dumpPerson()
  }
}

class Person {
  String personName
  int personAge
  def dumpPerson(){
    println "name is ${personName},age is ${personAge}"
  }
}

def person(Closure<Person> closure){
  Person p = new Person()
  closure.delegate = p
  closure.setResolveStrategy(Closure.DELEGATE_FIRST)
  closure(p)
}

运行结果如下:

Task :configClosure
name is 张三,age is 20

例子中我们设置了委托对象优先,为当前创建的Person实例,并且设置了委托模式,所以我们在使用person方法创建一个Person实例时,可以在闭包中直接对改Person实例进行配置。有没有发现和我们在Gradle中使用task创建一个Task的用法很像,其实在Gradle中有很多类似的用法,在Gradle中也基本都是使用delegate的方式使用闭包进行配置等操作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342