从Java到Kotlin(五)

函数与Lambda表达式

目录

一、函数声明与调用

二、参数和返回值

三、单表达式函数

四、函数作用域

五、泛型函数

六、尾递归函数

七、中缀表示法

八、Lambda表达式的语法

九、高阶函数与Lambda表达式

十、匿名函数

十一、内联函数

一、函数声明与调用

Java 中的方法使用 void 关键字声明:

Kotlin 中的函数使用 fun 关键字声明:

用法相似,加入有一个 User 类,里面有一个 foo() 函数,调用函数的代码如下:

Java代码

Kotlin代码

二、参数和返回值

声明有参数的函数,代码如下:

Java代码

Kotlin代码

Java先定义类型,后命名;Kotlin先命名,后定义类型,中间用冒号分隔。两者都是多个参数中间用逗号分隔。

如函数有返回值,代码如下:

Java代码

Kotlin代码

Java是把替换成返回值的类型,而Kotlin是把返回值声明在函数的末尾,并用冒号分隔。

两种语言声明参数和返回值的方式有点相似,而Kotlin还有更强大的功能,例如和 ,如下所示:

函数参数可以有默认值,当没有给参数指定值的时候,使用默认值

如果有默认值的参数在无默认值的参数之前,要略过有默认值的参数去给无默认值的参数指定值,要使用来指定值,有点绕我们看代码:

可变数量的参数

函数的参数可以用 vararg 修饰符标记,表示允许将可变数量的参数传递给函数,如下所示:

三、单表达式函数

在Kotlin中,如果函数的函数体只有一条语句,并且有返回值,那么可以省略函数体的大括号,变成单表达式函数。如下所示:

四、函数作用域

在 Kotlin 中函数可以在文件顶层声明,这意味着你不需要像一些语言如 Java 那样创建一个类来保存一个函数。此外除了顶层函数,Kotlin 中函数也可以声明在局部作用域、作为成员函数以及扩展函数。

1. 成员函数

成员函数是指在类或对象里定义的函数。

Java代码:

Kotlin代码:

2. 局部函数

Kotlin支持在函数内嵌套另一个函数,嵌套在里面的函数成为局部函数,如下所示:

运行代码,得到结果

而Java中没有局部函数这一概念。

五、泛型函数

泛型参数使用尖括号指定,如下所示:

Java代码

Kotlin代码

六、尾递归函数

尾递归函数是一个递归函数,用关键字来修饰,函数必须将其自身调用作为它执行的最后一个操作。当一个函数用修饰符标记并满足所需的形式时,编译器会优化该递归,留下一个快速而高效的基于循环的版本,无堆栈溢出的风险,举个例子:

先看一段代码

上面的函数是一个死循环,当我们调用函数后,会报StackOverflowError。这时可以用修饰符标记该递归函数,并将其自身调用作为它执行的最后一个操作,如下所示:

再次运行代码,无堆栈溢出。

七、中缀表示法

中缀表示法是调用函数的另一种方法。如果要使用中缀表示法,需要用 关键字来修饰函数,且要满足下列条件:

它们必须是成员函数或扩展函数;

它们必须只有一个参数;

其参数不得接受可变数量的参数。

下面来举个例子:

八、Lambda表达式的语法

Lambda表达式的语法如下:

Lambda 表达式总是括在大括号中;

其参数(如果有的话)在 -> 之前声明(参数类型可以省略);

函数体(如果存在的话)在 -> 后面。

举个例子:

如果Lambda表达式自动推断的返回类型不是,那么在Lambda表达式函数体中,会把最后一条表达式的值当做是返回值。所以上面的常量 的返回值是类型。如果要指定常量的返回值为类型,可以这样写:

当Lambda表达式只有一个参数的时候,那么它将可以省略这个唯一的参数的定义,连同也可以省略。如下所示:

上面说到如果Lambda表达式自动推断的返回类型不是,那么在Lambda表达式函数体中,会把最后一条表达式的值当做是返回值。举个例子:

九、高阶函数与Lambda表达式

高阶函数是将函数用作参数或返回值的函数,如下所示:

上面代码中是一个函数,拥有函数类型() -> String,接收一个String参数,当我们执行这行代码的时候,相当于执行了,并返回了字符串"Czh"。当我们调用时,将函数作为参数传入高阶函数,需要在该函数前加两个冒号作为标记。

Kotlin提供了Lambda表达式来让我们更方便地传递函数参数值。Lambda表达式总是被大括号括着;如果有参数的话,其参数在 之前声明,参数类型可以省略;如果存在函数体的话,函数体在 后面,如下所示:

如果函数的最后一个参数是一个函数,并且你传递一个Lambda表达

式作为相应的参数,你可以在圆括号之外指定它,如下所示:

十、匿名函数

匿名函数与常规函数一样,只是省略了函数名称而已。举个例子

匿名函数函数体是表达式,也可以是代码段,如下所示:

上面高阶函数的例子中的函数的第二个参数也可以传入一个匿名函数,如下所示:

十一、内联函数

1.内联函数

使用高阶函数会带来一些运行时的效率损失。每一个函数都是一个对象,并且会捕获一个闭包。 即那些在函数体内会访问到的变量。 内存分配(对于函数对象和类)和虚拟调用会引入运行时间开销。这时可以通过内联函数消除这类的开销。举个例子:

上面代码中,函数有一个函数类型的参数,通过Lambda表达式向函数传入参数值,Kotlin编译器会为Lambda表达式单独创建一个对象,再将Lambda表达式转换为相应的函数并调用。如果这种情况出现比较多的时候,就会很消耗资源。这是可以在函数前使用关键字,把Lambda函数内联到调用处。如下所示:

2.禁用内联

通过关键字,编译器将Lambda函数内联到调用处,消除了运行时消耗。但内联可能导致生成的代码增加,所以需要避免内联比较大的Lambda表达式。如果想禁用一些Lambda函数的内联,可以使用修饰符禁用该Lambda函数的内联,如下所示:

3.内联属性

关键字除了可以使函数内联之外,还能内联没有幕后字段(field)的属性,如下所示:

总结

本篇文章对比了Java方法和Kotlin函数在写法上的区别,也认识了Lambda函数和还列举了一些Kotlin函数中比较特别的语法,如中缀表示法等。可见Kotlin中的函数内容还是很多的,用法也相对复杂,但运用好Kotlin的函数,能使开发变得更简单。

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180228G050K500?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券