我是靠谱客的博主 孤独奇迹,这篇文章主要介绍Groovy语法之闭包,现在分享给大家,希望可以做个参考。

闭包概述

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

闭包格式

  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默认值是owner
    println(obj1() == obj2.owner)
    // 嵌套闭包delegate默认值也是owner
    def 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 = p
    println(upperCasedName())//Norman
    
    upperCasedName.delegate = t
    println(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 = p
    println(cl())//42
    
    cl.delegate = t
    println(cl())//42
    
    //修改代理策略
    cl.resolveStrategy = Closure.DELEGATE_ONLY
    cl.delegate = p
    println(cl())//42
    
    cl.delegate = t
    try {
        cl()
        assert false
    } catch (MissingPropertyException ex) {
        // "age" is not defined on the delegate
    }

最后

以上就是孤独奇迹最近收集整理的关于Groovy语法之闭包的全部内容,更多相关Groovy语法之闭包内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部