Java8 和 Scala 中的高阶函数

函数文本最大的优势就是可以像字符串或者对象等其他文本(literal)一样传送它。这种特性为构建高度紧凑和可重用代码提供无限的可能性。

1、我们的第一个高阶函数

当我们将一个函数文本传送给一个方法的时候,我们最主要的是一个接收方法参数的方法(这个确实很绕-_-|||),这类方法就叫做高阶函数。上文Swing例子中提到的 addActionListener 方法恰好属于这类。我们还可以定义自己的高阶函数来为自己提供许多便利。让我们看一个简单的例子:

def measure[T](func:=>T):T {
val start = System.nanoTime()
val result = func
val elapsed = System.nanoTime() - start;
print("The execution of this call took: %s ns".format(elapsed));
result
}
在这个例子中,我们声明了一个名为measure的方法用来计算这个名为func的函数文本的回调所需要的时间。func 方法的签名(signature)是它不接收任何参数并且返回一个泛型类型T。正如你所看到的,Scala中的函数并不一定需要参数尽管它们能够——而且往往也含有参数。

现在我们可以向 measure 方法中传递任何函数文本(或者方法)。

def myCallback = {
Thread.sleep(1000)
"I just took a poewrnap"
}
val result = measure(myCallback);
> The execution of this call took: 100244900 ns
从概念的角度讲我们所做的,就是将计算方法调用时间和实际的运算区分开来。我们构造了两块可以重用、松散耦合、类似于拦截器(interceptor)的代码块(measure和myCallback)

2、通过高阶函数实现重用

先看一个假设的例子,两个可重用构造略紧耦合:

def doWithContact(fileName:String, handle:Contact => Unit):Unit = {
try {
val contactStr = io.Source.fromFile(fileName).mkString
val contact = AContactParser.parse(contactStr)
handle(contact)
}
catch {
case e: IOException => println("couldn't load contact file: " + e);
case e: ParseException => println("coulnd't parse contact file: " + e);
}
}
doWithContact 方法从文件中读取电子名片之类的联系方式然后将数据提供给一个解析器(parser)将数据转化成为联系领域的对象。然后这个对象被传递给一个函数文本回调 handle。 doWithContact 方法 很函数文本均返回 Unit 类型,等同于java中的返回void的方法。

现在,我们可以定义各种各样的可以传递给 doWithContact 的回调函数:

val storeCallback = (c:Contact) => ContactDao.save(c)
val sendCallback = (c:Contact) => {
val msgBody = AConverter.convert(c)
RestService.send(msgBody)
}
val combineCallback = (c:Contact) => {
storeCallback(c)
sendCallback(c)
}
doWithContact("custerX.vcf", storeCallback)
doWithContact("custerY.vcf", sendCallback)
doWithContact("custerZ.vcf", combineCallback)
doWithContact("custerZ.vcf", combineCallback)
回调函数也可以通过内联传递:

doWithContact("custerW.vcf", (c:Contact) => ContactDao.save(c))
3、Java 8 中的高阶函数

java 8 中的等效实现看起来十分相似——使用目前的语法建议:

public interface Block<T> {
void apply(T t);
}
public void doWithContact(String fileName, Block<Contact> block) {
try {
String contacStr = FileUtils.readFileToString(new File(fileName));
Contact.apply(contact);
block.apply(contact);
}
catch (IOException e) {
System.out.println("cloudn't load contact file: " + e.getMessage());
}
catch (ParseException e) {
System.out.println("cloudn't parse contact file: " + e.getMessage());
}
}
//usage
doWithContact("custerX.vcf", c -> ContactDao.save(c))
4、使用高阶函数的益处

正如你见到的,函数帮助我们干净地将对象的创建和处理区分开来。通过这种方法,新的业务逻辑处理对象就可以轻易的添加进来而没有必要同对象创建逻辑相耦合。

结果就是,我们通过使用高阶函数来使我们的代码保持DRY(Dont't Repeat Yourself) 因而,程序员可以从一个非常细粒度的代码重用中获得最佳利益。

原文链接:http://my.oschina.net/atttx123/blog/66812
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值