1.3 万变不离其宗
虽然代码简化了,但是什么也没少,表面上再怎么变化,底层的实质永恒如一。
就拿上一节的Kotlin类定义来说,看起来只有一行,实质上编译出的class代码中什么也没少,所以写的时候把一些能省的代码省了,其实是留给了编译器去完成。所以要记住,只是表现形式变了,该有的东西一样都不少,这叫万变不离其宗。
那么哪些代码能省呢?答案很简单:能推导出来的代码就能省!举一个例子:Lambda表达式。其实Java 8中已经支持Lambda了,可以说Lambda是新式语法中的一个重要语法糖。初接触Lambda的人会感到很迷惑,主要是因为它的语法,虽然知道它的作用跟函数一样,但是看起来却很不像函数,比如下面这段Java:
fab.setOnClickListener(view -> Snackbar.make(view, "", Snackbar.LENGTH_LONG));
这是Android中常见的设置侦听器的代码,“fab”是一个按钮,setOnClickListener()方法用于设置响应按钮单击事件的侦听器,侦听器是一个类,主要作用就是包含一个回调方法,当然可以用Lambda来代替侦听器类,因为这可以少写很多代码。
小括号里就是一个Lambda,怎么解读这个Lambda呢?首先它是一个函数(当然准确地说它是一个函数对象,但现在不必深究),定义一个函数必须具备四要素:函数名、参数、函数体、返回值类型。那么这个Lambda具备这些要素吗?当然具备了,万变不离其宗!
首先说函数名。Lambda就是匿名函数,虽然有名字,但是因为用不到,所以匿名了。再说参数,“->”左边是参数、右边是函数体。返回值也是存在的,但不必像一般函数那样明确声明,而是靠推导而得。如何推导呢?看函数体最后一条语句的返回值类型。
其实可以让Lambda看起来更接近一般函数,比如参数放在小括号里、函数体放在大括号里,并为参数增加类型,具体如下:
fab.setOnClickListener((View view) -> { Snackbar.make(view, "", Snackbar.LENGTH_LONG); });
虽然看起来稍微顺眼点了,但是我们的原则是能省就省,所以前面的写法才是更好的。
如果这段代码改用Kotlin实现,会如何呢?请看:
fab.setOnClickListener { view -> Snackbar.make(view, "", Snackbar.LENGTH_LONG) }
Kotlin也支持Lambda,而且看起来与Java的写法区别不大,唯一的区别就是Lambda的所有部分都放在大括号中。这样的语法又带来一个好处:Kotlin可以更进一步,把简化做到极致——连方法调用的小括号都省掉,因为方法setOnClickListener()的参数只有一个,且其内容都放在了大括号中,所以可以将小括号省掉,编译器依然可以判定此种形式的函数调用语法。
现在我们知道了新式语法的简洁是靠编译器自动推导的,那么推导是如何进行的呢?
有时很简单,比如定义变量:
var aStr=""
根据初始值,一下就推导出aStr的类型是字符串。但是,如果像下面这样定义变量呢?
var bStr = null
这就不允许了,因为初始值null不属于任何类型,推导不出bStr的类型,而强类型语言是不允许在编译阶段有不确定的变量类型,所以此时必须明确指定类型:
var bStr:String? = null
为什么类型后面多了一个问号?后文会有详细解释。
为了让大家快速入门,下节将对新式语法的特征做一个总结。