Groovy语法之闭包

来源:互联网 发布:又拍云存储 域名 编辑:程序博客网 时间:2024/06/08 08:55

闭包概述

闭包就是一个特殊的匿名代码块,可以传递参数,有返回值,还能作为方法的参数进行传递。

闭包格式

  1. 闭包的格式定义如下:

    { [closureParameters -> ] statements }

    示例:

    { item++ }                                          { -> item++ }                                       { println it }                                      { it -> println it }                                { name -> println name }                            { String x, int y ->                                    println "hey ${x} the value is ${y}"}{ reader ->                                             def line = reader.readLine()    line.trim()}
  2. closureParameters :闭包参数是非必需的,与方法的参数十分类似,区别是:如果存在闭包参数,闭包参数与闭包语句之间需要使用箭头(->)的分割。

  3. 注意:如果没有指定参数,则默认存在一个it的参数,代表的是闭包本身。如下例子:

    def obj = {    println(it)}obj('hello')
  4. statements:同样,闭包语句则可以类比于方法体,功能也相同。

  5. 变量可作为闭包的载体,原因是:闭包其实是Groovy中的Closure类的实例。如下三种示例:

    def listener = { e -> println "Clicked on $e.source" }      //指明为Closure类型实例Closure callback = { println 'Done!' }                      //指明为Closure类型实例,并指定返回类型 Closure<Boolean> isTextFile = {    File it -> it.name.endsWith('.txt')                     }
  6. 执行闭包有两种方式:一是直接调用;二是通过调用Closure的call方法。如下代码:

    def obj = {    def item = 10    return ++item}// 直接调用println(obj())//call调用println(obj.call())
  7. 从字节码来看上述两种方式的区别:两种方式完全等效,都是通过call来完成

    public Object test() {    CallSite[] var1 = $getCallSiteArray();    class _test_closure1 extends Closure implements GeneratedClosure {        public _test_closure1(Object _thisObject) {            CallSite[] var3 = $getCallSiteArray();            super(Closures.this, _thisObject);        }        public Object doCall(Object it) {            CallSite[] var2 = $getCallSiteArray();            Object item = Integer.valueOf(10);            return var2[0].call(item);        }        public Object doCall() {            CallSite[] var1 = $getCallSiteArray();            return this.doCall((Object)null);        }    }    Object obj = new _test_closure1(this);    var1[2].callCurrent(this, var1[3].call(obj));    return var1[4].callCurrent(this, var1[5].call(obj));}

代理策略

  1. 代理在groovy的闭包中是非常重要的概念,与之相关的是this、owner和delegate这三种概念。

  2. this:指的是定义闭包所在的直接的外围类,具体有如下两种方式获取:

    class Test {    void run() {        // 方式一:使用getThisObject        def enclosingThisObject = { getThisObject() }        // 方式二:this操作符        def enclosingThis = { this }        def testThis = this        def print = "enclosingThisObject=${enclosingThisObject()},enclosingThis=${enclosingThis()},testThis=$testThis"        println(print)   }}def test = new Test()test.run()

    运行结果:

    enclosingThisObject=com.demo.test.cl.Test@4f209819,enclosingThis=com.demo.test.cl.Test@4f209819,testThis=com.demo.test.cl.Test@4f209819

    从字节码也可看出两种方式是等效的,因为this方式也会调用getThisObject,如下:

    public void run() {    CallSite[] var1 = $getCallSiteArray();    class _run_closure1 extends Closure implements GeneratedClosure {        public _run_closure1(Object _thisObject) {            CallSite[] var3 = $getCallSiteArray();            super(Test.this, _thisObject);        }        public Object doCall(Object it) {            CallSite[] var2 = $getCallSiteArray();            return var2[0].callCurrent(this);        }        public Object doCall() {            CallSite[] var1 = $getCallSiteArray();            return this.doCall((Object)null);        }    }    Object enclosingThisObject = new _run_closure1(this);    class _run_closure2 extends Closure implements GeneratedClosure {        public _run_closure2(Object _thisObject) {            CallSite[] var3 = $getCallSiteArray();            super(Test.this, _thisObject);        }        public Object doCall(Object it) {            CallSite[] var2 = $getCallSiteArray();            // this方式调用getThisObject方法            return this.getThisObject();        }        public Object doCall() {            CallSite[] var1 = $getCallSiteArray();            return this.doCall((Object)null);        }    }    Object enclosingThis = new _run_closure2(this);    Object print = new GStringImpl(new Object[]{var1[0].call(enclosingThisObject), var1[1].call(enclosingThis), this}, new String[]{"enclosingThisObject=", ",enclosingThis=", ",testThis=", ""});    var1[2].callCurrent(this, print);}

    注意:在内部类中定义闭包,那么this指的是这个内部类;同样,嵌套的闭包定义,this指的是外层闭包所在的类。如下实例:

    class EnclosedInInnerClass {    class Inner {        Closure cl = { this }    }    void run() {        def inner = new Inner()        assert inner.cl() == inner    }}class NestedClosures {    void run() {        def nestedClosures = {            def cl = { this }            cl()        }        assert nestedClosures() == this    }}

    小结:闭包需要依附于某个类中,不能单独存在;this其实是闭包与所在外部类的通信桥梁。

  3. owner: 指的是定义闭包的直接外围对象,可以是类或者闭包。与this相似,区别在于嵌套闭包,如下实例:

    class NestedClosures {    void runOwner() {        def nestedClosures = {            def cl = { owner }            cl()        }        assert nestedClosures() == nestedClosures    }    void runThis() {        def nestedClosures = {            def cl = { this }            cl()        }        assert nestedClosures() == this    }}

    嵌套闭包中this与owner的区别:this是外围类的实例,而owner则是外层闭包实例。

    小结:闭包中的this侧重于直接外围类,而owner则偏向于闭包的宿主对象,它们都是闭包与外部环境的通信桥梁。

  4. delegate:获取闭包的delegate有如下两种方式,其返回的默认值是owner。

    // 方式一:调用getDelegate()方法def obj1 = { getDelegate() }// 方式二:delegate关键字def obj2 = { delegate }// delegate默认值是ownerprintln(obj1() == obj2.owner)// 嵌套闭包delegate默认值也是ownerdef enclosed = {      { -> delegate }.call()    }assert enclosed() == enclosed

    如下通过不同的代理对象,闭包的行为是不同的:

    class Person {    String name}class Thing {    String name}def p = new Person(name: 'Norman')def t = new Thing(name: 'Teapot')def upperCasedName = { delegate.name.toUpperCase() }upperCasedName.delegate = pprintln(upperCasedName())//NormanupperCasedName.delegate = tprintln(upperCasedName())//Teapot
  5. 代理策略:上述例子中的闭包能正常运行,是因为闭包的代理策略影响了编译闭包代码时的解析策略。分为如下几种策略:

    • Closure.OWNER_FIRST:OWNER优先策略,也是默认策略,优先从owner中寻找属性或方法,找不到再从delegete中寻找。
    • Closure.DELEGATE_FIRST:与OWNER_FIRST相反。
    • Closure.OWNER_ONLY: 只在owner中寻找属性或方法。
    • Closure.DELEGATE_ONLY: 只在delegate中寻找属性或方法。
    • Closure.TO_SELF: 前提是用户需要实现的Closure的子类,只会在闭包自身中寻找属性或方法。
    class Person {    String name    int age    def fetchAge = { age }}class Thing {    String name}def p = new Person(name: 'Jessica', age: 42)def t = new Thing(name: 'Printer')def cl = p.fetchAge// 注意:cl的默认代理对象就是p,可以省略// cl.delegate = pprintln(cl())//42cl.delegate = tprintln(cl())//42//修改代理策略cl.resolveStrategy = Closure.DELEGATE_ONLYcl.delegate = pprintln(cl())//42cl.delegate = ttry {    cl()    assert false} catch (MissingPropertyException ex) {    // "age" is not defined on the delegate}
原创粉丝点击