Groovy基础

<<Android Gradle权威指南》阅读笔记——Groovy基础

​ 本文讲述Groovy 基础Groovy是基于JVM虚拟机的一种动态语言,又在此基础上增加了很多动态类型和灵活特性,比如支持闭包,支持DSL,可以说它是一门非常灵活的动态脚本语言。

​ 每个Gradlebuild脚本文件都是Groovy脚本文件你可以在里面写任何符合Groovy语法的代码,比如定义类,声明函数,定义变量等;而Groovy又完全兼容Java,这就意味着你可以在build脚本文件里写任何的Java代码。


1. 字符串

Groovy中,单引号和双引号都可以定义一个字符串常量(Java里单引号定义一个字符),不同的是单引号标记的是纯粹的字符串常量,而不是对字符串里表达式做运算,单引号没有运算能力,双引号可以:

  • 类型:
task printStringClass << {
     def str1 = '单引号'
     def str2 = "双引号"
    ​
     println "单引号定义的字符串类型:"+str1.getClass().name
     println "双引号定义的字符串类型:"+str2.getClass().name
    }
./gradlew printStringClass 输出
    Task :printStringClass
    单引号定义的字符串类型:java.lang.String
    双引号定义的字符串类型:java.lang.String</pre>
  • 运算
task printStringVar << {
     def name = "张三"
    ​
     println '单引号的变量计算:${name}'
     println "双引号的变量计算:${name}"
    }</pre>
./gradlew printStringVar 输出
 Task :printStringVar
    单引号的变量计算:${name}
    双引号的变量计算:张三

2. 集合

Groovy完全兼容了Java的集合,并进行了扩展,使操作变得更容易。

  • List

    Grroovy中实现List非常简单,同时还提供了下标索引负下标范围索引迭代操作(each)

task printList << {
     def numList = [1,2,3,4,5,6];
     println numList.getClass().name //输出时可以看出 numList 是一个 ArrayList
    ​
     println numList[1]//访问第二个元素 下标索引 下标从 0 开始
     println numList[-1]//访问最后一个元素 负下标 
     println numList[-2]//访问倒数第二个元素 负下标
     println numList[1..3]//访问第二个到第四个元素 范围索引 由”.."分开
    ​
     numList.each{//迭代操作
     println it //it 正在迭代的元素,这里涉及闭包的知识,下文会讲解
     }
    }
./gradlew printList 输出
Task :printList
    java.util.ArrayList
    2
    6
    5
    [2, 3, 4]
    1
    2
    3
    4
    5
    6
  • Map

    Map的用法和List类似,区别在于它的值是K:V`键值对

task printMap << {
     def mapl = ['width':1920,'height':1080]
     println mapl.getClass().name //输出可以看出mapl是一个LinkedHashMap
    ​
     //访问可以采用map[key]或者map.key两种方式
     println mapl['width']
     println mapl.height
    ​
     mapl.each{//迭代操作
     println "Key:${it.key},Value:${it.value}"//此处的it是一个Map.Entry实例
     }
    }
./gradlew printMap 输出
 Task :printMap
    java.util.LinkedHashMap
    1920
    1080
    Key:width,Value:1920
    Key:height,Value:1080

关于集合的更多方法后续会补充,有兴趣的可以自行先了解

3. 方法

通过了解Groovy方法和Java方法的不同,更利于我们明白Gradle脚本里的代码

  • 括号可以省略

    Groovy调用一个方法比Java灵活的多,可以省略(),在定义DSL时非常有用并且书写方便

task invokeMethod << {
     //这两种调用方式结果一直,但第二种更简洁
     methodl (1,2)
     methodl 1,2
    }
    ​
    def methodl(int a, int b){
     println a+b
    }
./gradlew invokeMethod 输出
 Task :invokeMethod
    3
    3
  • return 可以不写

    Groovy在没有return时,会将方法执行过程中的最后一句作为返回值

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 //执行到此处 返回a
     }else{
       b //执行到此处 返回b
     }
    }
./gradlew printMethodReturn 输出
 Task :printMethodReturn
    add1:2,add2:5
  • 代码块可以作为参数传递

    通过each方法,我们可以直接的理解这个问题

    //最初的写法
    numList.each({println it})
    ​
    //经过格式化
    numList.each({
       println it
    })
    ​
    //Groovy中方法的最后一个参数为闭包,可以放到外面
    numList.each(){
       println it
    }
    ​
    //去掉方法的括号
    numList.each{
       println it
    }

4. JavaBean

JavaBean中繁琐的getter/setterGroovy中得到了很大改善

task helloJavaBean << {
   Person p = new Person()
​
   println "名字是:${p.name}"//此时name为赋值,返回null
   p.name = 'tom'
   println "名字是:${p.name}"//已赋值,返回tom
   println "年龄是:${p.age}"//未定义成员变量时,通过getAge()方法也可获取age,但不能修改值
}
​
class Person{
   private String name
   public int getAge(){
     12
 }
}

./gradlew helloJavaBean 输出

 Task :helloJavaBean
名字是:null
名字是:tom
年龄是:12

5. 闭包

闭包是Groovy的一个非常重要的特性,可以说他是DSL的基础。

task helloClosure << {
 //使用自定义闭包
   customEach {
     println it
   }

​
 //多个参数
   eachMap {k,v ->
     println "${k} is ${v}"
    }
}
​
def customEach(closure){//唯一参数,用于接收一个闭包(代码块)
   //模拟一个集合,开始迭代
   def numList = [1,2,3]
   numList.each{
     closure(it)
   }
}
​
def eachMap(closure){//此处的闭包传递两个参数k v
   def mapl = ["name":"tom","age":18]
   mapl.each{
     closure(it.key,it.value)
   }
}

./gradlew helloClosure 输出

 Task :helloClosure
1
2
3
name is tom
age is 18
  • 闭包委托

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

task helloDelegate << {
   new Delegate().test{
     println "thisObject:${thisObject.getClass()}" //thisObject优先级最高
     println "owner:${owner.getClass()}"//owner优先级次之
     println "delegate:${delegate.getClass()}"
     //delegate优先级最低,但是owner==delegate
     //闭包内方法的执行顺序:thisObject>owner>delegate
     method3()
     it.method3()
   }
}
​
def method3(){
   println "Context this:${this.getClass()} in root"
   println "method3 in Delegate"
}
​
class Delegate{
   def method3(){
     println "Delegate this:${this.getClass()} in Delegate"
     println "method3 in Delegate"
   }
​
   def test(Closure<Delegate> closure){
     closure(this)
   }
}

./gradlew helloDelegate 输出

 Task :helloDelegate
thisObject:class build_edqlj0scrowqqm8jgfgirxcz4
owner:class build_edqlj0scrowqqm8jgfgirxcz4$_run_closure10
delegate:class build_edqlj0scrowqqm8jgfgirxcz4$_run_closure10
Context this:class build_edqlj0scrowqqm8jgfgirxcz4 in root
method3 in Delegate
Delegate this:class Delegate in Delegate
method3 in Delegate

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

task configClosures << {
   man {//在闭包类直接对Man实例配置
     manName = "tom"
     manAge = 19
     dumpMan()
   }
}
​
class Man{
   String manName
   int manAge
​
   def dumpMan(){
     println "name is ${manName},age is ${manAge}"
   }
}
​
def man(Closure<Person> closure){
   Man p = new Man();
   //设置委托对象为当前创建的Man实例
   closure.delegate = p 
   //委托模式优先
   closure.setResolveStrategy(Closure.DELEGATE_FIRST);
   closure(p)
}

./gradlew configClosures 输出

 Task :configClosures
name is tom,age is 19

6. DSL

DSL(Domain Specific Language)——领域特定语言(专门关注某一领域的语言)

Gradle就是一门DSL,它基于Groovy专门解决自动化构建的DSL

到这Groovy基础就简单介绍完了,后续我们再学习新的Gradle知识,欢迎持续关注

原文链接 更多类容

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容