Groovy 代码块:闭包

闭包不是一个新的概念,但是它通常用在函数式语言中,它允许执行一个任意指定好的代码块。

在面向对象语言,方法对象模式(Method-Object pattern)通常用来模拟一个行 为:为一个目的定义一个独立的方法接口,这个接口的实例能够传递一组参数给方法,然后调用这个接口方法。

一个好的例子是java.io.File.list(FilenameFilter)方法,FilenameFilter接口只有一个方法,这个方法只有一个目的,就是从list方法返回的列表可以通过FilenameFilter的方法进行过滤。

遗憾的是,这导致了一些不必要的增殖类型,并且由于广泛使用独立逻辑指针导致代码难以理解。java使用匿名内部类来达到这种效果,但是语法是难以理解的,并且他们的意义被限制在调用方法的内部,和访问调用方法的内部变量。groovy允许将闭包简明的内联在代码中,清晰而强大,实际上提升方法对象模式到语言顶级类的位置。

由于闭包对于java程序员来说是全新的概念,所以java程序员也许需要一定的时间来适应闭包。一个好消息是使用闭包的起步非常容易以至于你很难注意到闭包是一个新的概念,当发现闭包的优势之后,你会感觉非常酷。 通俗的说,一个闭包是一个用花括号围起来的语句块,像别的任何代码块,为了传递参数给闭包,闭包有一组可选的参数列表,通过“->”表示列表的结束,通过例子最容易理解闭包了,图2.5显示一个简单的闭包,这个闭包被传递给list.each方法,这个列表有1,2,3三个元素。

List.each方法需要一个简单的参数——闭包,然后遍历list的元素,每次遍历时将当前的元素传递给闭包,有多少个元素,闭包就被调用多少次。在这个例子中,闭包的主体是打印传递给闭包的参数,这个参数在这个例子中的名称为“entry”。

思考一个稍微复杂点的问题:如果n个人在会议室,并且每两个人之间进行碰杯,有多少次碰杯?图2.6 是5个人的描述图,每一条线代表一次碰杯。

为了回答这个问题。我们使用类Integer的upto方法,这个方法用来从当前整数值到结束的整数值之间,为每个整数做一些工作,我们应用这个方法来处理所有到达会议室的人员,在一个人员到达会议室之后,这个人和已经到达会议室的每个人进行碰杯,通过这个方法,每一个人都将与会议室的所有人碰杯。

列表2.5显示了计算碰杯数的代码,我们保留碰杯的总数量,并且在每个客人到达的时候,我们累加这个客户的碰杯数(会议室的客人数 - 1),最后,我们使用高斯原则来验证这个结果——100个人有4950次碰杯。

表 2.5 使用闭包计算所有在会议室的客人之间的碰杯数def totalClinks = 0 def partyPeople = 100 1.upto(partyPeople) { guestNumber -> clinksWithGuest = guestNumber-1 totalClinks += clinksWithGuest } assert totalClinks == (partyPeople*(partyPeople-1))/2 这个代码在java中 怎么实现呢?在java中,也许使用像下面代码一样的处理方式,类声明和main方法的声明被忽略://Java int totalClinks = 0; for(int gue stNumbe r = 1; gue stNumber <= partyPeople; gue stNumber++) { int clinksWithGuest = gue stNumber-1; totalClinks += clinksWithGuest; } 注意guestNumber在java代码中出现了4次而在groovy代码中只出现了2次,不要觉得这好像是一件小事情,程序员应该通过最简单的代码尽可能清晰的描述问题,使用2次表述比使用4次是一个重要的简化。

upto方法封装和隐藏了怎么样迭代一个整数的逻辑,这也意味着这个逻辑在代码中只出现了一次(在upto的实现中),结果与java计算的结果是一样的,但在java中确出现了重复的变量数量。