3.1 使用闭包:闭包的便利性

  1. 当在 Java 中定义用于注册事件处理器的方法参数或者创建短小的胶水代码时,会创建匿名内部类。该特性看上去是一个不错的想法,但是没过多久,开发者们就发现,它们变得非常冗长,尤其是对那种确实非常短的单方法接口的实现。Groovy 中的闭包就是去掉了那种冗长感的短小的匿名方法。

  2. 闭包是轻量级的,短小、简介。而且将会是在 Groovy 中使用最多的特性之一。过去传递匿名类实例的地方,现在可以传递闭包。

  3. 闭包是从函数式编程的 Lambda 表达式派生而来的。闭包是 Groovy 最强大的特性之一,而且语法上非常优雅。闭包不是简单地替代匿名方法,它还可以变成解决有效高内存需求问题的一种通用工具。

  4. 举个栗子:

def sum(n) {
    total = 0
    for (int i = 2; i <= n; i += 2) {
        total += i
    }
    total
}

println "Sum of even numbers for 1 to 100 is ${sum(100)}"

def product(n) {
    prod = 1
    for (int i = 2; i <= n; i += 2) {
        prod = prod * i
    }
    prod
}

println "Product of even numbers for 1 to 100 is ${product(10)}"


def sqr(n) {
    squared = []
    for (int i = 2; i <= n; i += 2) {
        squared << i
    }
    squared
}

println "Squares of even numbers for 1 to 100 is ${sqr(10)}"

打印结果:

Sum of even numbers for 1 to 100 is 2550
Product of even numbers for 1 to 100 is 3840
Squares of even numbers for 1 to 100 is [2, 4, 6, 8, 10]

上面的例子中,进行循环的代码是相同的。差别在于处理的是和、积还是集合。如果想在偶数上执行一些其他操作,还要重复这些遍历数字的代码。所以得想办法去掉这些重复。

  1. 从上面共同任务的这一函数入手:当挑选出一个偶数时,直接将其传递给一个代码块来处理。比如可以让代码块简单地打印传入的数字:
def pickEven(n, block) {
    for (int i = 2; i <= n; i += 2) {
        block(i)
    }
}

pickEven(10, { println it })

打印结果:

2
4
6
8
10

pickEven() 是一个高阶函数,即以函数为参数,或返回一个函数作为结果的函数。pickEven() 方法对值进行迭代,但不同的是它将值传递给了一个代码块。在 Groovy 中,这个匿名代码块称为 闭包
变量 block 保存了一个指向闭包的引用。可以像传递对象一样传递闭包。变量名没有必要一定命名为 block,可以使用其他任何合法的变量名。

  1. 上面的例子优化如下:
pickEven(10, { println it })
total1 = 0
pickEven(100, { total1 += it })
println "total1 is $total1"

prod1 = 1
pickEven(10, { prod1 *= it })
println "prod1 is $prod1"

squared1 = []
pickEven(10, { squared1 << it })
println "squared1 is $squared1"

打印结果:

total1 is 2550
prod1 is 3840
squared1 is [2, 4, 6, 8, 10]

你可能感兴趣的:(3.1 使用闭包:闭包的便利性)