Android Gradle学习系列(三)-核心语法讲解与实战之闭包详解

前言

这一篇我们将讲解Groovy闭包,主要从三个层次讲解

  • Groovy闭包基础详解
  • Groovy闭包使用详解
  • Groovy闭包进阶详解

1.闭包基础详解

在这里插入图片描述

闭包概念

就是一段代码块,和我们的方法类似,用{}包裹起来

我们看下例子
在这里插入图片描述

闭包参数

使用->来区分我们的参数和闭包体.->前面的是参数.后面的是闭包体
举个例子
在这里插入图片描述
Groovy的闭包中有一个默认参数it
在这里插入图片描述

闭包返回值

我们回忆下方法的返回值.有两种:一种是有返回值的,一种是没有返回值的.但是在我们闭包中稍微有点不同,我们的闭包是一定有返回值的,接下来我们写个例子验证下:

  • 第一种,闭包体有返回值的
    在这里插入图片描述
  • 第二种,闭包体没有返回值的
    在这里插入图片描述
    这里这个null也是返回值的一种,这就说明在闭包中是一定会有返回值的

2.闭包使用详解

在这里插入图片描述

闭包进阶详解

与基本类型的结合使用

我们呢先求一个整数的阶乘,如果我们用Java来实现的话,需要循环调用,但是在Groovy中就可以通过闭包来实现,我们写个例子

//求指定number的阶乘
int fab(int number) {
    //结果
    int result = 1

    1.upto(number, { num -> result *= num })

    return result
}

这里我们用的是upto这个方法,这个方法有两个参数,第一个是指定到多少,第二个就是闭包,表示每次增加要做什么
我们这个写法就是说从1一直到我们定义的这个number,每次都让我们这个result乘以我们的number

我们让number等于5,也就是5的阶乘,结果为120,我们运行下我们这段代码,看看输出的结果是不是和我们想的一样
在这里插入图片描述
我们知道其实求阶乘一定会用到循环的,所以我们看下upto的源码

   public static void upto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) {
        int self1 = self.intValue();
        int to1 = to.intValue();
        if (self1 > to1) {
            throw new GroovyRuntimeException("The argument (" + to + ") to upto() cannot be less than the value (" + self + ") it's called on.");
        } else {
            for(int i = self1; i <= to1; ++i) {
                closure.call(i);
            }

        }
    }

我们看到其实这个方法内部也是调用的循环

那除了upto方法可以实现阶乘,还有没有别的方法呢?答案是有的,与之对应的还有一个方法叫downTo,我们接下来用downTo方法实现下

int fab2(int number) {
    //结果
    int result = 1
    number.downto(1) {
        num -> result *= num
    }
    return result
}

写法基本上和upto没啥区别,upto是从小到大,downto是从大到小
我们运行下这段代码
在这里插入图片描述
结果是一样的
同样我们也贴下源码

 public static void downto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) {
        int self1 = self.intValue();
        int to1 = to.intValue();
        if (self1 < to1) {
            throw new GroovyRuntimeException("The argument (" + to + ") to downto() cannot be greater than the value (" + self + ") it's called on.");
        } else {
            for(int i = self1; i >= to1; --i) {
                closure.call(i);
            }

        }
    }

除了上面2中常用的以外,我们一般还会用到times这个方法,这里我们想求从0到100的求和,我们就可以用这个方法实现

// 从0循环到number
int cal(int number) {
    int result = 0
    number.times {
            // times(Closure)只接收一个闭包,把闭包写到括号外,括号可以省略
        num -> result += num
    }
    return result
}

我们看下结果
在这里插入图片描述
这里有个地方要注意下,就是这个times方法是不包括你定义的这个值的,就是说比如我们要算0到100的和,我们就需要传101,我们看下源码就可以了

 public static void times(Number self, @ClosureParams(value = SimpleType.class,options = {"int"}) Closure closure) {
        int i = 0;

        for(int size = self.intValue(); i < size; ++i) {
            closure.call(i);
            if (closure.getDirective() == 1) {
                break;
            }
        }

    }

我们看见源码中是小于号,没有等于,同时我们也发现这个times方法是从0开始的,所以它不能用于求上面我们说的阶乘

与String结合使用包参数

字符串的遍历

这个主要就是调用each方法

String str = 'This is Greathfs'
// each:遍历每个字符
str.each {
    String temp -> print temp
}

我们运行下
在这里插入图片描述
这个each方法就是我们调用者的本身,我们下面验证下,传一个空的闭包进去看看
在这里插入图片描述

查找符合条件的第一个

这个主要就是调用find方法,find有很多重载方法,我们主要就是调用下参数是闭包的
在这里插入图片描述

在这里插入图片描述

查找符合条件所有

这里呢调用的是findAll方法
在这里插入图片描述

遍历每个字符,只要满足条件就返回true

在这里插入图片描述

遍历每个字符,所有都要满足条件才会返回true

在这里插入图片描述

遍历每个字符,经过闭包处理后,添加进list中返回

在这里插入图片描述

OK,我们回头看下思维导图,剩下的与数据结构结合使用和与文件等结合使用我们将在后续讲解完数据结构和文件时在讲解

3.Groovy闭包进阶详解

在这里插入图片描述

3.1闭包关键变量

闭包关键变量(this、owner、delegate)

在这里插入图片描述
我们看见输出日志这里this,owner,delegate,的值是一样的,既然一样,那为什么要定义三个变量呢?

  • this:这个关键字在我们Java表示当前类的方法或者变量,同样在Groovy中这个this就表示闭包定义处的类
  • owner:代表闭包定义处的类或者对象
  • delegate:代表任意对象,默认与owner一致

接下来我们写一个稍微复杂点的例子,我们定义一个内部类,然后在里面定义闭包和方法,方法里面在定义闭包,同时我们打印三者
在这里插入图片描述
我们运行打印下结果
在这里插入图片描述
我们看见结果完全一样,并且指向的是Person的实例对象而不是Groovy闭包进阶,也就是说this,owner,delegate永远指向最近的类

接下来我们在闭包中定义一个闭包,我们在看下结果如何
在这里插入图片描述

这里我们就发现这三者并不是完全相同的了,this指向的是我们外面的Groovy闭包进阶这个类实例对象,忽略nestCliser,而ownerdelegate他俩都指向的是我们的内部innerCloser对象,并且与this不相同

我们之前说过delegate默认是与owner一样,那我们修改下delegate是不是就和owner不一样了呢?我们写段代码验证下
在这里插入图片描述
这里我们就发现三者完全不相同了
我们总结下:

  • 在大多数据情况下,thisownerdelegate的值是一样的,delegate默认与owner相同
  • 在闭包中定义闭包时,thisownerdelegate的值是不一样的。(this指的是闭包定义处的类对象,owner指的是闭包定义处类中的闭包对象)
  • 在手动修改了闭包delegate时,ownerdelegate的值才会不一样

3.2闭包委托策略

闭包委托策略(Closure.OWNER_FIRST、Closure.OWNER_ONLY、Closure.DELEGATE_FIRST、Closure.DELEGATE_ONLY)

这里我们以老师和学生为例说下
在这里插入图片描述

我们首先打印下学生的toString方法
在这里插入图片描述

学生的toString方法打印的是学生里面的name,我们如果想改变这个值,让学生的toString打印出来是老师的名字应该怎么弄呢?我们第一想法是修改构造方法内里内容不就行了,这里我们通过另外一种办法实现它,我们之前说过delegate这个变量,如果我们把prettydelegate指向我们的老师是不是就可以呢?我们验证下
在这里插入图片描述
我们看下打印结果在这里插入图片描述
咦,好像并没有生效,但是理论上应该生效才对啊,哪里出了问题呢?因为我们还没有给它指定委托策略,每个闭包都有自己的委托策略,默认是OWNER_FIRST,也就是先从owner指向的对象寻找,我们这里owner指向的是Student这个类,所以我们改下这个委托策略,改成从delegate指向的对象寻找
在这里插入图片描述
这样就对了
假如我们老师类中没有name怎么办,我们把老师类中的变量name改成name1,我们输出看看下结果
在这里插入图片描述

我们看见输出又会变成学生中的XiaoMing,因为我们制定的委托策略是Closure.DELEGATE_FIRST,优先从delegate中寻找,找不到就会继续从owner中寻找 ,那如果我们把委托策略改成Closure.DELEGATE_ONLY会变成什么样呢?我们打印下
在这里插入图片描述
直接报错了,因为在我们的老师中没有name这个变量

发布了87 篇原创文章 · 获赞 319 · 访问量 149万+

猜你喜欢

转载自blog.csdn.net/Greathfs/article/details/102925536