Android函数式编程技巧:Kotlin语言中的Lambda表达式

添加时间:15-09-25   添加人:  点击:

使用得当的话, 函数式编程方式的确功能强大。尽管Java 8包含了一些函数式编程机制,可是你能够想象Android开发人员无法很快就能用上(甚至永远不能)。为解决这个问题,替代语言出现了。

现代语言中的函数式编程

函数式编程依赖于函数和不变性,这样调用一个函数始终会返回相同的结果。通常,折中既是完美,所以大多数现代开发语言(如: Kotlin或Scala)都在一种开发语言中,融合了过程式编程和函数式编程方法,并在这两方面拥有最为精彩的灵感和创意。有些问题使用函数式编程方式解决更好,还有一些问题,坚持使用过程式编程方式解决则更直接。

在Android平台使用Kotlin语言的Lambda表达式

Lambda表达式是定义匿名函数的简单形式。由于Lambda表达式避免了在抽象类和接口中编写明确的函数声明,进而也避免了类的实现部分,因此十分有用。在Kotlin中,可以使用函数作为另一个函数的参数。例如,可以将需要回调(callback)的函数简化为如下代码:

[cpp] view plaincopy
fun runAsync(callback: () -> Unit){ 
    ... 
    callback() 

这种用法十分直观。做一些转换后(稍后会看到),函数的调用方式可以得到简化:

[cpp] view plaincopy
runAsync { toast("Finished") } 
另一个件让人赏心悦目的事情是,Kotlin使用单独的函数编写接口,这些接口就好像是Lambda表示式。这样就可以大规模地简化代码。举个例子来说更容易明白,想象一下,我们要为视图编写一个典型的setOnClickListener()方法:

使用Java语言编写的接口:

[java] view plaincopy
public interface OnClickListener { 
    void onClick(View v); 

然后需要编写匿名类以实现该接口:

[java] view plaincopy
view.setOnClickListener(new OnClickListener() { 
    @Override 
    public void onClick(View v) { 
        Toast.makeText(v.getContext(), "Click", Toast.LENGTH_SHORT).show(); 
    } 
}); 
这可以转换为Kotlin代码(使用Anko 库函数toast):

[cpp] view plaincopy
view.setOnClickListener(object : OnClickListener { 
    override fun onClick(v: View) { 
        toast("Click") 
    } 
}) 
如前所述,Kotlin允许对Java类库进行一些优化,任何具备接口的函数都可以用函数替代。就像定义了setOnclickListener()方法那样去工作:

[cpp] view plaincopy
fun setOnClickListener(listener: (View) -> Unit) 
Lambda表达式由箭头左侧函数的参数(小括号里面的内容)定义的,将值返回给箭头右侧。在这里,将得到的View返回给Unit,了解了这些内容,可以对上述代码稍做简化:

[cpp] view plaincopy
view.setOnClickListener({ view -> toast("Click")}) 
真是微妙的差别啊!在定义函数时,必须在箭头左边使用中括号并指定参数值,而函数执行代码在右边。如果左边没有使用参数,甚至可以省去左边部分:

[cpp] view plaincopy
view.setOnClickListener({ toast("Click") }) 
如果被执行的函数是当前函数的最后一个参数的话,也可以将这个作为参数的函数放到圆括号外面:

[cpp] view plaincopy
view.setOnClickListener() { toast("Click") } 
最后,如果函数是唯一的参数,还可以去掉原来的小括号:

[cpp] view plaincopy
view.setOnClickListener { toast("Click") } 
比起起初的Java代码,目前的代码量小于原来的五分之一,且更容易理解。令人印象深刻。Anko给出一个(本质上说是函数名的)简化版本,由之前展示过的扩展函数组成,该函数也由上述形式实现::

[cpp] view plaincopy
view.onClick { toast("Click") } 
扩展语言

幸亏有这些转换,可以创建自己的生成器和代码块。Kotlin标准库提供一些像with那样有趣的函数。下面是更简单的实现方式::

[cpp] view plaincopy
inline fun <T> with(t: T, body: T.() -> Unit) { t.body() } 
这个函数会获取一个类型T的对象,还会获得一个函数,该函数被用作扩展函数。实现的过程仅仅解决了对象,并让对象执行函数。由于函数的第二个参数是另一个函数,所以可以将它放到括号外面。因此,可以直接创建代码块,也可以使用对象的this关键字,还能够直接使用公共属性和对象的函数:

[cpp] view plaincopy
with(forecast) { 
    Picasso.with(itemView.ctx).load(iconUrl).into(iconView) 
    dateView.text = date 
    descriptionView.text = description 
    maxTemperatureView.text = "${high.toString()}o" 
    minTemperatureView.text = "${low.toString()}o" 
    itemView.onClick { itemClick(forecast) } 

结论

Lambda表达式的强大还仅依赖于我们的想象。如果没有使用过函数式编程方式的话,那么掌握Lambda表示式就还需要实践。这样做是不吃亏的。如果想要学习更多Lambda表达式和Kotlin语言的相关内容,从我正在编写的书中可以收获更多。

(翻译/张挥戈 友情审校/白云鹏)

文章来源:antonioleiva

作者简介:Antonio Leiva,Android工程师、热爱用户体验、界面设计,目前就职于Plex, Inc。


译者简介:

张挥戈,长期从事计算机软件开发、项目管理和产品设计工作,曾在多家移动互联网公司任技术总监。关注Android平台相关技术以及其他平台客户端软件开发相关话题。

预告:  2015中国移动开发者大会(MDCC 2015)将于10月14日-16日在北京新云南皇冠假日酒店召开。大会特设九大技术专场:平台与技术(iOS)、平台与技术(Android)、平台与技术(跨平台)、产品与设计、游戏开发、企业移动化、虚拟现实专场、硬件开发与技术、嵌入式开发。大会将聚集国内最具实力的产品技术团队,与开发者一道进行最前沿的探讨与交流。