Groovy闭包

# 闭包

  • 闭包的基础知识
  • 闭包的使用
  • 闭包 this,owner,delegate 的理解
  • 总结

## 闭包的基础知识

闭包就是一段可以使用参数的代码片段,每个闭包会被编译成继承groovy.lang.Closure 类的类(具体查看编译后的.class文件即可),这个类有一个叫 call 方法,通过该方法可以传递参数并调用这个闭包。

### 定义一个闭包

闭包定义的格式

//方式1:定义参数
{闭包参数,闭包参数,闭包参数...->闭包体}

//方式2:无定义参数,${it] 为默认的参数
{闭包体}

指定闭包参数

def closure = {String name,int age->
    println "name is ${name} and the age is ${age}"
}

不指定闭包参数

def closure2 = {
    println "the param is ${it}"
}

闭包就是一个对象

//指定闭包的类型
Closure<Boolean> isImageFile = {
   String filePath ->
        return filePath.endsWith('.png') || filePath.endsWith('.jpg')
}

println isImageFile("xxxx.png")//true

### 闭包的返回值

闭包一定是有返回值的,这就是闭包有别于方法的一点,方法是可以没有返回值的。

def closuer = {String name,int age->
    println "name is ${name} and the age is ${age}"
}
//因为没有调用 return ,因此返回 null
println closuer('六号表哥',26)//null

### 闭包的参数

  • 闭包的参数是可选的;
  • 有一个默认的参数;
  • 闭包多个参数使用 , 隔开;
  • 参数的类型是可选的;
  • 闭包参数接受可变参数
//不指定参数类型,多个参数用,个隔开
def clouser = {  name,  age ->
    println "name is ${name} and the age is ${age}"
}

//不指定闭包参数
def clouser = { 
    println "closure"
}

//闭包 it 为暗指参数
def clouser2 = {
    println "the param is ${it}"
}


//可变参数
def concat = { String... params ->
     params.join()
}

println concat.call("1","2","3")//123

### 调用闭包

在 Groovy 中调用闭包有两种方式

  • closuer.call(参数)
  • closuer()
def closuer = {String name,int age->
    println "name is ${name} and the age is ${age}"
}
//调用方式1
closuer.call('六号表哥',26)//name is 六号表哥 and the age is 26
//调用方式2
closuer('六号表哥',26)//name is 六号表哥 and the age is 26

//使用 ${it} 表示默认参数
def closuer2 = {
    println "the param is ${it}"
}

closuer2('使用默认参数')//the param is 使用默认参数

## 闭包的使用

  • 闭包与基本数据类型的集合
def result = 0;
//从10递增到20,累加每一个值
10.upto(20) {

    int value ->
        result += value
}

println result

  • 闭包与String字符串的结合
String name = "Hello Groovy"

//name.each {
//    String str ->
//        print str + " "//H e l l o   G r o o v y
//}

//查找第一个符合条件的值
println name.find {
    String str ->
        if (str.equals("o")) {
            return str
        }
        return null

}

println name.findAll {
    if (it.equals("o")) {
        return it;
    }
    return null
}.toListString()//[o, o, o]


String book = "20180701"
println book.every {
    String str ->
        return str.isInteger()//true
}

println name.any {
    return it.equals("o")//true
}


String str = "name:liuhaobiaoge,age:26,level:middle,1:update,0:canel"
str.findAll {
    if (it.isInteger()) {
        return it;
    }
    return null
}.collect {
    String value ->
        print value.toInteger() * 2 + "  "//4  12  2  0
}
  • 闭包与结合数据结构集合
def list = [1, 2, 3, 4]

println list.every { it ->
    return it > 0
}
  • 闭包与文件结合

TODO

### 通过源码分析 upto 方法是如何使用闭包的?

upto 方法它的职责很单一就是一个递增的功能,但是每递增一次,对应的需要给外界知道,那么就是通过执行一段闭包,将这个值暴露出去,这种设计很好,它不会影响 upto 方法内部的执行逻辑。

  • 调用 uptp 方法,传入闭包
def result = 0;
//从10递增到20,累加每一个值
10.upto(20) {

    int value ->
        result += value
}

println result
  • 进入 upto 源码

代码很简单,具体每一行代码都加了注释

/**
 * Iterates from this number up to the given number, inclusive,
 * incrementing by one each time.
 *
 * @param self    a Number
 * @param to      another Number to go up to
 * @param closure the closure to call
 * @since 1.0
 */
public static void upto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) {
    //self的值就是10
    int self1 = self.intValue();
    //to1的值就是20
    int to1 = to.intValue();
    //满足条件
    if (self1 <= to1) {
        //从10遍历到20
        for (int i = self1; i <= to1; i++) {
            //每一个值传递给我们先前定义的闭包closure,并执行该闭包。
            closure.call(i);
        }
    } else
       ...
}

## this,delegate,ower 的区别

### 定义

  • this 表示定义闭包的类

  • owner 表示定义闭包的类或者闭包(闭包内还是可以定义闭包的)

  • delegate 默认与 owner 一致,可以手动修改 delegate 的值

### 区别

  • 一般情况下这三者是一样的。
  • 闭包中定义在闭包中,thisowerdelegate不一致。
  • 如果修改 delegate ,那么 owerdelegate 就不一致。

默认情况下 thisowner,delegate 是一样的。

class Enclosing {

    void run() {
        def closure = {
            println this//Enclosing@69997e9d
            println owner//Enclosing@69997e9d
            println delegate//Enclosing@69997e9d
        }

        closure()
    }
}

闭包中的this就是定义闭包的类对象

验证1:测试闭包的 this 和定义闭包的类的 this 是否一致

class Enclosing {

    void run() {
        def whatIsThisObject = { getThisObject() }

        assert whatIsThisObject() == this

        println whatIsThisObject()//Enclosing@3514a4c0
        
        //this就是Enclosing对象
        println this//Enclosing@3514a4c0

        def whatIsThis = { this }
        //返回闭包的this对象
        println whatIsThis()//Enclosing@3514a4c0
    }
}

new Enclosing().run()

验证2:使用内部类来验证闭包的this和定义闭包的类的this是一样的

class EnclosdInnerClass {
    class Inner {
        //这里返回的this就是Inner对象
        def closure = { this }
    }

    void run() {
        def inner = new Inner()
        
        println inner.closure()//EnclosdInnerClass$Inner@6babf3bf
        //打印内部类对象
        println inner//EnclosdInnerClass$Inner@6babf3bf
        //这个是外部类对象
        println this//EnclosdInnerClass@3059cbc
    }
}

new EnclosdInnerClass().run()

验证3:验证闭包的this和定义闭包的类的this是一样的


class Person {

    String name
    int age

    String toString() {
        "${name} is $age year old"
    }


    String dump() {
        def closure = {
            //this 表示就是定义closure 闭包的类,这个类就是Person
            //因此这里调用的toString就是Person的toString()方法
            def msg = this.toString()
            println msg
            return msg
        }
        closure()
    }
}
//如果不知道构造参数,那么在传参时就要执行参数的名称
Person p = new Person(name: "六号表哥", age: 26)
p.dump()//六号表哥 is 26 year old

闭包中的 owner 就是定义闭包的闭包或者类对象

验证1:

class OwnerEnclosing {
    void run() {
        def whatIsOwnerMethod = {
            getOwner()
        }
        //返回闭包的owner对象
        println whatIsOwnerMethod()//OwnerEnclosing@6e0f5f7f
        //返回定义闭包类的对象
        println this//OwnerEnclosing@6e0f5f7f

        def whatIsOwner = { owner }
        println whatIsOwner()//OwnerEnclosing@6e0f5f7f

    }
}

OwnerEnclosing ownerEnclosing = new OwnerEnclosing()
ownerEnclosing.run()

验证2:

class OwnerEnclosdInnerClass {
    class Inner {
        def closure = { owner }
    }

    void run() {
        def inner = new Inner()
        //返回 closure 这个闭包的owner对象
        println inner.closure()//OwnerEnclosdInnerClass$Inner@53ce1329
        //返回内部类,也就是定义闭包的类对象
        println inner//OwnerEnclosdInnerClass$Inner@53ce1329
    }
}

new OwnerEnclosdInnerClass().run()

验证3:

class NestedClosure {
    void run() {
        def closure = {

            def cls = { owner }
            //返回的cls闭包的owner,也就是closure闭包对象
            cls()
        }
        
        println closure()//NestedClosure$_run_closure1@32502377
        println closure//NestedClosure$_run_closure1@32502377

    }

}

new NestedClosure().run()

闭包中的 deleagate 一般情况下和 owner 一致的,但是可以修改

class DelegateEnclosing {
    void run() {

        def cls1 = { getDelegate() }

        def cls2 = { delegate }

        println cls1()//DelegateEnclosing@7bab3f1a
        println cls2()//DelegateEnclosing@7bab3f1a
        println this//DelegateEnclosing@7bab3f1a

        def enclosed = {
            //这里返回的是定义闭包的闭包对象,也就是enclosed闭包对象
            { -> delegate }.call()
        }

        println enclosed()//DelegateEnclosing$_run_closure3@12aba8be
        println enclosed//DelegateEnclosing$_run_closure3@12aba8be

    }
}

new DelegateEnclosing().run()

验证:闭包的delegate是可以修改的

class P {
    String name
}

class Q {
    String name
}


P pp = new P(name: "pp")
Q qq = new Q(name: "qq")

def closure = {
    delegate.name.toUpperCase()
}

//将闭包的deleagte指向pp
closure.delegate = pp

println closure()//PP

closure.delegate = qq
println closure()//QQ

## 总结

在本节中,简单的总结了闭包的相关概念,定义,使用,以及this,owner,delegate几个关键字的理解。闭包在 Groovy 中应用很广泛,本节将闭包的应用分为与基本数据类型结合的闭包,与String 字符串结合的闭包,与数据结构结合的闭包,与文件结合的闭包(还没学习,不知道怎么耍,TODO),仅仅通过上面所总结的还是不够的,接下来还要好好深入学习其 Closure 相关的知识点。

「记录于2018-07-01晚」

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值