Java语言中的函数编程
利用闭包和高阶函数编写模块化的Java代码
级别:初级AbhijitBelapurkar(abhijit_3710167@qq.com),高级技术架构师,InfosysTechnologiesLimited2004年7月13日如果您从事大型企业项目开发,您就会熟悉编写模块化代码的好处.良构的,模块化的代码更容易编写,调试,理解和重用.Java开发人员的
问题是,函数编程范型长期以来只是通过像Haskell,Scheme,Erlang和Lisp这样的特殊语言实现的.在本文中,作者AbhijitBelapurkar展示了,如何使用像闭包(closure)和高阶函数(higherorderfunction)这样的函数编程结构,在Java语言中编写良构的,模块化的代码.Java语言中常被忽视的一个方面是它被归类为一种命令式(imperative)编程语言.命令式编程虽然由于与Java语言的关联而相当普及,但是并不是惟一可用的编程风格,也不总是最有效的.在本文中,我将探讨在Java开发实践中加入不同的编程方法——即函数编程(FP).
命令式编程是一种用
程序状态描述计算的方法.使用这种范型的编程人员用语句改变程序状态.这就是为什么,像Java这样的程序是由一系列让
计算机执行的命令(或者语句)所组成的.另一方面,函数编程是一种强调表达式的计算而非命令的执行的一种编程风格.表达式是用函数结合基本值构成的,它类似于用参数调用函数.
本文将介绍函数编程的基本特点,但是重点放在两个特别适用于Java开发框架的元素:闭包和高阶函数.如果您曾经使用过像Python,Ruby或者Groovy(请参阅参考资料)这样的敏捷开发语言,那么您就可能已经遇到过这些元素.在这里,您将看到在Java开发框架中直接使用它们会出现什么情况.我将首先对函数编程及其核心元素做一个简短的,概念性的综述,然后用
常用的编程场景展示,用结构化的方式使用闭包和高阶函数会给Java代码带来什么好处.
什么是函数编程?
在经常被引用的论文"WhyFunctionalProgrammingMatters"(请参阅参考资料)中,作者JohnHughes说明了模块化是成功编程的关键,而函数编程可以极大地改进模块化.在函数编程中,编程人员有一个天然框架用来开发更小的,更简单的和更一般化的模块,然后将它们组合在一起.函数编程的一些基本特点包括:支持闭包和高阶函数.支持懒惰计算(lazyevaluation).使用递归作为控制流程的机制.加强了引用透明性.没有副作用.我将重点放在在Java语言中使用闭包和高阶函数上,但是首先对上面列出的所有特点做一个概述.
闭包和高阶函数
函数编程支持函数作为第一类对象,有时称为闭包或者仿函数(functor)对象.实质上,闭包是起函数的作用并可以像对象一样操作的对象.与此类似,FP语言支持高阶函数.高阶函数可以用另一个函数(间接地,用一个表达式)作为其输入参数,在某些情况下,它甚至返回一个函数作为其输出参数.这两种结构结合在一起使得可以用优雅的方式进行模块化编程,这是使用FP的最大好处.
懒惰计算
除了高阶函数和仿函数(或闭包)的概念,FP还引入了懒惰计算的概念.在懒惰计算中,表达式不是在绑定到变量时立即计算,而是在求值程序需要产生表达式的值时进行计算.延迟的计算使您可以编写可能潜在地生成无穷输出的函数.因为不会计算多于程序的其余部分所需要的值,所以不需要担心由无穷计算所导致的out-ofmemory错误.一个懒惰计算的例子是生成无穷Fibonacci
列表的函数,但是对第n个Fibonacci数的计算相当于只是从可能的无穷列表中提取一项.
命令式编程命令式编程这个名字是从自然语言(比如英语)的祈使语气(imperativemood)衍生出来的,在这种语气中宣布命令并按照执行.除Java语言之外,C和C++是另外两种广泛使用的,符合命令式风格的高级编程语言.
递归
FP还有一个特点是用递归做为控制流程的机制.例如,Lisp处理的列表定义为在头元素后面有子列表,这种表示法使得它自己自然地对更小的子列表不断递归.
引用透明性
函数程序通常还加强引用透明性,即如果提供同样的输入,那么函数总是返回同样的结果.就是说,表达式的值不依赖于可以改变值的全局状态.这使您可以从形式上推断程序行为,因为表达式的意义只取决于其子表达式而不是计算顺序或者其他表达式的副作用.这有助于验证正确性,简化算法,甚至有助于找出优化它的方法.
副作用
副作用是修改
系统状态的语言结构.因为FP语言不包含任何赋值语句,变量值一旦被指派就永远不会改变.而且,调用函数只会计算出结果——不会出现其他效果.因此,FP语言没有副作用.