函数文本最大的优势就是可以像字符串或者对象等其他文本(literal)一样传送它
这种特性为构建高度紧凑和可重用代码提供无限的可能性
我们的第一个高阶函数
当我们将一个函数文本传送给一个方法的时候我们最主要的是一个接收方法参数的方法(这个确实很绕_|||)这类方法就叫做高阶函数上文Swing例子中提到的 addActionListener 方法恰好属于这类我们还可以定义自己的高阶函数来为自己提供许多便利让我们看一个简单的例子
def measure[T](func:=>T)T {
val start = SystemnanoTime()
val result = func
val elapsed = SystemnanoTime() start;
print(The execution of this call took: %s nsformat(elapsed))
result
}
在这个例子中我们声明了一个名为measure的方法用来计算这个名为func的函数文本的回调所需要的时间func 方法的签名(signature)是它不接收任何参数并且返回一个泛型类型T正如你所看到的Scala中的函数并不一定需要参数尽管它们能够而且往往也含有参数
现在我们可以向 measure 方法中传递任何函数文本(或者方法)
def myCallback = {
Threadsleep()
I just took a poewrnap }
val result = measure(myCallback)
> The execution of this call took: ns
从概念的角度讲我们所做的就是将计算方法调用时间和实际的运算区分开来我们构造了两块可以重用松散耦合类似于拦截器(interceptor)的代码块(measure和myCallback)
通过高阶函数实现重用
先看一个假设的例子两个可重用构造略紧耦合
def doWithContact(fileName:String handle:Contact => Unit)
Unit = {
try {
val contactStr = ioSourcefromFile(fileName)mkString
val contact = AContactParserparse(contactStr)
handle(contact)
}
catch {
case e: IOException => println(couldnt load contact file: + e)
case e: ParseException => println(coulndt parse contact file: + e)
}
}
doWithContact 方法从文件中读取电子名片之类的联系方式然后将数据提供给一个解析器(parser)将数据转化成为联系领域的对象然后这个对象被传递给一个函数文本回调 handle doWithContact 方法 很函数文本均返回 Unit 类型等同于java中的返回void的方法
现在我们可以定义各种各样的可以传递给 doWithContact 的回调函数
val storeCallback = (c:Contact) => ContactDaosave(c)
val sendCallback = (c:Contact) => {
val msgBody = nvert(c)
RestServicesend(msgBody)
}
val combineCallback = (c:Contact) => {
storeCallback(c)
sendCallback(c)
}
doWithContact(custerXvcf storeCallback)
doWithContact(custerYvcf sendCallback)
doWithContact(custerZvcf combineCallback)
doWithContact(custerZvcf combineCallback)
回调函数也可以通过内联传递
doWithContact(custerWvcf (c:Contact) => ContactDaosave(c))
Java 中的高阶函数
java 中的等效实现看起来十分相似使用目前的语法建议
public interface Block<T> {
void apply(T t)
}
public void doWithContact(String fileName Block<Contact> block)
{
try {
String contacStr = FileUtilsreadFileToString(new File(fileName))
Contactapply(contact)
blockapply(contact)
}
catch (IOException e)
{
Systemoutprintln(cloudnt load contact file: + egetMessage())
}
catch (ParseException e)
{
Systemoutprintln(cloudnt parse contact file: + egetMessage())
}
}
//usage doWithContact(custerXvcf c > ContactDaosave(c)
)
使用高阶函数的益处
正如你见到的函数帮助我们干净地将对象的创建和处理区分开来通过这种方法新的业务逻辑处理对象就可以轻易的添加进来而没有必要同对象创建逻辑相耦合
结果就是我们通过使用高阶函数来使我们的代码保持DRY(Dontt Repeat Yourself) 因而程序员可以从一个非常细粒度的代码重用中获得最佳利益