构建工具是一个可编程的工具,能够以执行和有序的任务来表达满足需要的自动化过程 构建工具就是用来让我们不在做机械重复的事情,解放我们的双手

DSL

领域特定语言,基本思想是“求专不求全”,不像通用目的语言那样目标覆盖一切软件问题,而是专门针对某一特定问题的计算机语言,通俗的讲就是行话

Gradle

是一个构建工具,基于 groovy ,并且是一种 DSL , Gradle 样板文件的代码少,这是因为它的 DSL 被设计用于解决特定的问题:贯穿软件的生命周期,从编译,到静态检查,直到打包和部署。

Groovy

是一个编程语言,

  • 一个功能强大,灵活动态语言,他是在 Java 平台上的一种简洁,数学并且易学的语言,大大提高了开发者的效率
  • 属于脚本语言
  • 提供更简单,更灵活的语法,可以在运行时动态进行类型检查
  • 执行 groovy 脚本的时候, groovy 会讲起编译成 Java 字节码,然后通过 JVM 来执行该 Java 类,所以,在执行的时候,由于 Groovy 代码已经被编译为 Java 代码, JVM 根本就不知道自己运行的是 Groovy 代码,

    Groovy简单语法

字符串

def d="world"  

def a="hello $d " //双引号的内容,如果符号中有$的话,会先求$表达式的值,在输出
println a  //hello world

def b='hello  $d' //如果是单引号的话,不对$符号转义
println b  //hello  $d

容器类

  • List 链表 对应 Java 中 的ArrayList
  • Map键值表 对应 Java 中的LinkedHashMap
  • Range范围 对 List 的扩展
List 链表

格式 []

def list=[4,5]
 def list2 = new ArrayList<String>(list1) //创建新集合
 def list3 =  ['a', 1 , 'a', 'a', 2.5, 2.5f, 2.5d, 'hello', 7g , null , 9 as  byte] `//可以不同类型,并且可以重复,可以为null`
def list=[1,'2', true ,"helei",null]
println list.size() //打印长度

//list.get(-1) //数组角标越界
println list[-2] //倒数第二个 helei
println list[-1] //倒数第一个  null
println list[0] //整数第一个  1
println list[3] //整数第四个  helei

println list.getAt(-2) //倒数第二个 helei
println list.getAt(2) //整数第二个 true

//集合遍历
list.each{ //不带下标
    print "item $it   "
}
//相当于下一种, each 方法接受一个闭包参数,
list.each({
    it->print "$it   "
})

list.eachWithIndex{ //带下标的
 it ,i->
    println "$i,$it  "
}

def list=[5,"hello",'world', null ,true]

println list[8] //null
println list.size() //5

list[10]=100 //设置第 11 个元素为100
println list.size() //集合大小为 11
//没有赋值的元素为null
println list // [5, hello , world , null , true , null , null , null , null , null , 100]

Map 键值表

使用[:]创建 Map 注意其中的冒号。冒号左边是 key ,右边是 Value 。key必须是字符串, value 可以是任何对象。另外, key 可以用’‘或”“包起来,也可以不用引号包起来。

def map=[name:"zhangsan","sex":true,id:123]
println map.size()
println map.get("name")
println map.name
println map.age //要是想获取没有属性的值,返回的是null

//添加值
map.addone="age" //添加一个属性为 addone ,值为”age“
map.put("aa",false) //添加一个属性为 aa ,值为flase

//集合遍历
map.each{
    entry->//entry 是 map 的一个属性,
    println "key:$entry.key value: $entry.value"
}

map.eachWithIndex{
 entry ,i->
   println "$i   key:$entry.key value: $entry.value"
}

map.each{
 key ,value->
    println "key: $key value: $value"
}

map.eachWithIndex{
 key , value ,i->
   println "$i   key:$key value: $value"
}
Range 类

是 List 的一个变体,能够很方便的创建有顺序的集合

  • 使用 .. 创建左右都包含的Range
  • 使用.. <创建左包含,右边不包含的Range
def range=5..8 //[5, 6 , 7 , 8]
println range

range=5..<8  //[5, 6 , 7] 不包含8
println range
println range.from+" , "+range.to //打印集合的起始值和末尾值 5  7

for(i in range){
    println "hello $i"
}
(1..10).each{//each 方法遍历,和 List 一样
    i->
    print "hello $i  "
}

def getRate(year){
    //特殊用法,用在 switch 语句中
    switch (year){
        case 1..10://如果输入的年份在 1 到 10 之间,执行
            interestRate=0.076
        break
         case 11..25://如果年份在 11 到 25 之间,执行
            interestRate=0.052
        break
        default :interestRate=0.037
    }
}

println getRate(2)  //0.076
println getRate(22)  //0.052
println getRate(32)  //0.037

Groovy 中的闭包

闭包是一段开放的,匿名的代码,用大括号{}括起来的代码块,这个代码块在调用的时候触发,

闭包格式

{
  [closureParameters ->]
  statements
}

闭包[closureParameters ->] 是可选的,看起来像是一个 List ,并且这些参数的类型可以不写

例如

{ String x, int y -> //参数                                
    println "hey ${x} the value is ${y}" //statement语句
}

创建闭包

闭包是一种类型,所以定义的时候要用=给它赋值,这是跟方法的本质区别 三种方法

// 使用 def 声明一个闭包
def listener={e -> println "Clicked on $e.source"}

// 使用指定类型 Closure 声明一个闭包
Closure callback={ println 'Done !'} //这个同时省略了参数

//使用泛型,生命一个固定返回类型的闭包

Closure<Boolean > isTextFile={
  File it ->it.name.endsWith('.txt')//返回 boolean 类型
}

调用闭包

闭包是一个匿名代码块,不能像调用方法那样调用,

  1. 无参闭包
  def code={123}
  println code()//调用该闭包
  println code.call()//另外一种闭包方式
  1. 带参数的闭包
      Closure isOldNumber={
       int  i-> //声明参数, int 可以省略
       i%2==1  //可以省略 return 语句
      }
      println isOldNumber(32)
      println isOldNumber.call(4)
    

闭包参数说明

  1. 普通的参数
    • 可以不写参数类型
    • 可以给参数一个默认值
  Closure closureWithTwoArgs =//使用指定类型 Closure 定义闭包,
  {
 a ,b ->// 无参数类型,
    a+b  //传入不能相加的类型会报错
  }

  println closureWithTwoArgs(1,2) //3
  println closureWithTwoArgs(1,2.5)// 3.5
  println closureWithTwoArgs(1,'2')// 12  因为'2'转换成相应的 AICCS 码表对应的值了
  println closureWithTwoArgs(1,"q")// 1q 这种是把数字 1 当成了字符串拼接了

  //默认参数
  def closureWithTwoArgsAndDefalutValue={
 int a ,int b=2 ->
      a+b
  }

  println closureWithTwoArgsAndDefalutValue(1) //3
  println closureWithTwoArgsAndDefalutValue(1,3)// 3.5
  //println closureWithTwoArgsAndDefalutValue(1,'2')// 报错,类型已经指定
  1. 隐式参数

如果闭包没有定义参数的话,则隐含一个参数,这个参数名字叫 it ,它保存了返回这个闭包的一个值,

def greeting={"hello ,$it !"}//隐含参数 it ,这个 it 是任意参数类型

//相当于
Closure greetingT={
  it ->
  //return "hello $it !"  //GString 用法
  return "hello,"+it+"!"
}

println greeting("world")//hello , world !
println greeting(1)//hello , 1 !
println greetingT("world")//hello, world !


def isOddNumber={it %2==1}// 这种情况下 it 类型就是int

println isOddNumber(3)
// println isOddNumber(3.5) //报错
// println isOddNumber('3')// 报错


def noParamClousre={-> true}
//绝对不能传递参数的
println noParamClousre()
// println noParamClousre("111") 报错
  1. 可变参数
def aMethod ={
    int... args -> // ... 表示可变
    int sum=0;
    args.eachWithIndex{// 遍历求和
 it ,i->
        sum=sum+args[i]
    }
    return sum
}
println aMethod(1, 2 ,3)

闭包的 Delegation 代理

Groovy 中的闭包具有能够改变代理或代理策略的能力,使得我们能够使用它设计很优美的 DSL 语言

  1. 理解 this ,owner Groovy 中的闭包内置了 3 个不同的对象,可以直接使用
    • this 闭包躲在的最近的类 .class
    • owner 定义闭包的宿主,不仅仅是类,还可能是一个闭包
    • delegate 代理

class NestedClocure {
    void run(){
        def nestedClosure={ //嵌套闭包
           def cl={  owner} //owner 值的就是该闭包的宿主,即nestedClosure
           println cl() //NestedClocure$_run_closure1@33f6a532

            def cl2={this}// this 指的是最近的 class ,即NestedClocure.class
            println cl2()  //NestedClocure@d9081e1

        }
       println  nestedClosure()
       println  nestedClosure  //NestedClocure$_run_closure1@4658ef71
       //println  nestedClosure()==nestedClosure
    }
}

def n=new NestedClocure()
n.run()
  1. 理解delegate this 和 owner 是 Groovy 内置在 Closure 中 的对象,那么 delegate 就是用户指定的对象,用于 Closure 使用。 delegate 默认使用的是owner
class Enclosing {
    void run(){
        def cl={getDelegate()}// 使用 getDelegate() 方法获取 Closure 的delegate
        def cl2={delegate}// 使用delegate

        println cl()==cl2() //true
        println cl()==this  //true
        def enclosed={
            {-> delegate}.call()
        }
        println enclosed()==enclosed  //true
    }
}

def e=new Enclosing()
e.run()

delegate 可以设置为不同的对象


class Person {
    String name
}

class Thing {
    String name
}

def p=new Person(name:'Norman')
def t=new Thing(name : 'Teapot')

//定义一个闭包,使用 delegate 获取名字,并返回大写值
def upperCassName={delegate.name.toUpperCase()}

upperCassName.delegate=p  //设置为 p ,则返回NORMAN
println  upperCassName()=='NORMAN'

upperCassName.delegate=t //设置为 p ,则返回TEAPOT
println  upperCassName()=='TEAPOT'

// delegate 对象可以透明使用,即不需要在方法前面显示声明delegate

def p1=new Person(name : 'helei')

//并没有写delegate.name,默认使用 owner , owner 没有 name 属性,所以使用 delegate 的 name 属性
def cl={name.toUpperCase()}

cl.delegate=p1
println cl()=="HELEI"
  1. delegate strategy 代理的代理策略 delegate 的策略默认是Closure.OWNER_FRIST,即 owner 优先,所有在宿主没有属性,就会去 delegate 中查查,如果 delegate 也没有,就报错了,
delegate 的策略
  • Closure.OWNER_FIRST
  • Closure.DELEGATE_FIRST
  • Closure.OWNER_ONLY
  • Closure.DELEGATE_ONLY
  • Closure.TO_SELF

class Person{
    String name
    int age
    def fetchAge={age}
}

class Thing{
    String name
}

def p=new Person(name:'helei',age:42)

def t=new Thing(name: 'Printer')
def cl=p.fetchAge
cl.delegate=p
println  cl()

cl.delegate=t
println cl()// 42 owner 优先, fetachAge 是一个闭包,他的 owner 是Person

cl.resolveStrategy=Closure.DELEGATE_ONLY //修改策略
cl.delegate=p
println cl() //42

cl.delegate=t
//修改策略后,仅在 delegate 查找,因为 Thing 中没有有 Age 属性,所以报错
// println cl() //Thing 中没有 Age 属性,所以报错

例子解析

dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
    }
  1. dependencies 是一个函数名,接受的参数是一个闭包类型,这是一个方法调用,而不是函数定义,因为在groovy中方法调用是可以省略()
    dependencies ({
         classpath 'com.android.tools.build:gradle:2.1.2'
     })
    

    注意和上一个比较,在大括号外部添加了一对小括号

  2. {} 实际上是一个 groovy 的闭包类型的参数,并且这个闭包是无参数的,相当于
    {it -> classpath 'com.android.tools.build:gradle:2.1.2'
     }
    
  3. 闭包里面由执行了 classpath 这个方法,而 classpath 方法的调用同样省略了(),实际上是
    classpath ('com.android.tools.build:gradle:2.1.2')
    

    所以,整个代码补全后相当于

    dependencies ({
      it ->   classpath('com.android.tools.build:gradle:2.1.2')
     })
    

task clean(type: Delete) {
    delete rootProject.buildDir
}
  1. task 是一个方法,参数因为中间没有逗号,所以只有一个,
    task ( clean(type: Delete) {
     delete rootProject.buildDir
    }
    
  2. clean是一个方法。里面有两个参数,一个是 Map ,一个是闭包 即
    def clean(Map type,Closure cl){
     type.type
    }
    

    把执行的 clean 返回的结果传递给方法task

  3. clean(type: Delete) 是往 clean 的 Map 集合中存放一个键值对,键是 type ,值是 Delete ,
  4. 因为根据 Groovy 的语法特性,当一个方法的最后一个参数是闭包,可以将这个闭包写在()外面。
     clean(type: Delete) {
     delete rootProject.buildDir
    }
    

    所以相当于

     clean(type: Delete, {
     delete rootProject.buildDir
    })
    
  5. 所以,整个改编后,
    task (
      clean(type: Delete, {
       delete rootProject.buildDir
      })
    )
    //一个一个单独写出来,就是如下所示
    def closure={delete rootProject.buildDir}
    def result=clean(type:Delete,closure())
    task result
    

    搬运地址: