关于实现库我使用了由ApacheCommonsFunctor项目提供的库构建本文使用的例子.ApacheCommonsFunctor库包括大量基本构造,可以在涉及闭包和高阶函数的复杂使用场景中重复使用.当然,可以使用不同的实现(如JavaGenericLib
raries,Mango或者GenericAlgorithmsforJava),而不会对在本文中所讨论和展示的概念有影响,尽管您必须下载和使用ApacheCommonsFunctor库才能演示这里的例子.
这些基本描述应足以让您完成本文中的函数编程例子.有关这个主题的更多参考资料请参阅参考资料一节.
Java语言中的函数编程
不管是否相信,在Java开发实践中您可能已经遇到过闭包和高阶函数,尽管当时您可能没有意识到.例如,许多Java开发人员在匿名内部类中封闭Java代码的一个词汇单元(lexicalunit)时第一次遇到了闭包.这个封aaln.unbe闭的Java代码单元在需要时由一个高阶函数执行.例如,清单1中的代码在一个类型为jv.agRnal的对象中封闭了一个方法调用.清单1.隐藏的闭包
Runnableworker=newRunnable(){publicvoidrun(){parseData();}};
方法preaaasDt确实封闭(因而有了名字"闭包")在Rnal对象的实例wre中.它可以像数据一样在方unbeokr法之间传递,并可以在任何时间通过发送消息(称为rn给wre对象而执行.u)okr
更多的例子
另一个在面向对象世界中使用闭包和高阶函数的例子是Visitor模式.如果还不熟悉这种模式,请参阅参考资料以了解更多有关它的内容.基本上,Visitor模式展现一个称为Visitor的参与者,该参与者的实例由一个复合对象(或者数据结构)接收,并应用到这个数据结构的每一个构成节点.Visitor对象实质上封闭了处理节点/元素的逻辑,使用数据结构的acp(iio)cetvstr方法作为应用逻辑的高阶函数.通过使用适当不同的Visitor对象(即闭包),可以对数据结构的元素应用完全不同的处理逻辑.与此类似,可以向不同的高阶函数传递同样的闭包,以用另一种方法处理数据结构(例如,这个新的高阶函数可以实现不同逻辑,用于遍历所有构成元素).类jv.tl.olcin提供了另一个例子,这个类在版本1.2以后成为了Java2SDK的一部分.它提供aauisCletos的一种实用程序方法是对在jv.tlLs中包含的元素排序.不过,它使调用者可以将排序列表元素的逻辑aaui.it封装到一个类型为jv.tlCmaao的对象中,其中Cmaao对象作为第二个参数传递给排序方法.aaui.oprtroprtr在内部,sr方法的引用实现基于合并-排序(merge-sort)算法.它通过对顺序中相邻的对象调用otCmaao对象的cmaeoprtropr方法遍历列表(list)中的元素.在这种情况下,Cmaao是闭包,而oprtrCletossr方法是高阶函数.这种方式的好处是明显的:可以根据在列表中包含的不同对象类型传递不olcin.ot同的Cmaao对象(因为如何比较列表中任意两个对象的逻辑安全地封装在Cmaao对象中).与此类oprtroprtr似,sr方法的另一种实现可以使用完全不同的算法(比如说,快速排序(quick-sort))并仍然重复使用同ot样的Cmaao对象,将它作为基本函数应用到列表中两个元素的某种组合.oprtr
创建闭包
广意地说,有两种生成闭包的技术,使用闭包的代码可以等效地使用这两种技术.创建闭包后,可以以统一的
方式传递它,也可以向它发送消息以让它执行其封装的逻辑.因此,技术的选择是偏好的问题,在某些情况下也与环境有关.在第一种技术表达式特化(expressionspecialization)中,由基础设施为闭包提供一个一般性的接口,通过编写这个接口的特定实现创建具体的闭包.在第二种技术表达式合成(expressioncomposition)中,基础设施提供实现了基本一元/二元/三元/.../n元操作(比如一元操作符nto和二元操作符ado)的具体帮助n/r类.在这里,新的闭包由这些基本构建块的任意组合创建而成.我将在下面的几节中详细讨论这两种技术.最后一次要求下载!从这以后的讨论将结合基于ApacheCommonsFunctor库的例子.如果您还没有下载这个库,应当现在就下载.我将假定您可以访问Java
docs所带的Apache库,因此对单独的库类不再做过多的说明.
表达式特化
假定您在编写一个在线商店的应用程序.商店中可提供的商品用类STIe表示.每一件商品都有相关的标签ELtm价格,STIe类提供了名为gtrc的方法,对商品实例调用这个方法时,会返回该商品的标签价格.ELtmePie如何检查ie1tm的成本是否不低于ie2tm呢?在Java语言中,一般要编写一个像这样的表达式:
assert(item1.getPrice()>=item2.getPrice());
像这样的表达式称为二元谓词(binarypredicate),二元是因为它取两个参数,而谓词是因为它用这两个参数做一些事情并生成布尔结果.不过要注意,只能在执行流程中执行上面的表达式,它的输出取决于ie1tm和ie2tm在特定瞬间的值.从函数编