1 闭包概述
闭包,Clousure。在Java中表现为Lambda表达式,在Koltin中表现为函数类型变量(或者也叫做Lambda表达式)。
其定义:java为什么匿名内部类的参数引用时final? - 胖胖的回答
一个依赖于自由变量的函数
处在含有这些自由变量的一个外围环境
这个函数能够访问外围环境里的自由变量
2 Kotlin和Java的闭包对比
在java8中,java中的闭包类型依然不能直接地修改外部环境的变量的引用,因此就有了众所周知的:匿名内部类的实例对外部环境的变量的访问,都需要让外部环境的变量加上final关键字。
在Kotin中,这一点被改进了,Kotlin中的闭包是功能健全的闭包。
3 代码
下面用简单的代码来对比java和kotlin的闭包类型变量在访问外部环境变量时的差异。
先定义了一个类型:鸟
class Bird(private val wordToSing: String) {fun sing() {log("I sing $wordToSing")}}
3.1 Kotlin
fun main() {var bird: Bird? = Bird("i 'm a testing bird.")val fun1 = {bird?.sing()bird = null}val fun2 = {if (bird != null) {log("bird is alive")} else {log("bird is destroyed")}}fun2()fun1()fun2()}
在上述代码中,有两个闭包:fun1和fun2,他们的外部环境是main()函数,外部环境中的变量是var bird变量,那么两个闭包中都自由地对这个外部变量进行了读写。跑上述代码,打印:
bird is aliveI sing i 'm a testing bird.bird is destroyed
3.2 Java
public class Test {public static void main(String[] args) {Bird bird = new Bird("i 'm a testing bird");Runnable fun1 = () -> {bird.sing();bird = null;};Runnable fun2 = () -> {if (bird != null) {UtilsKt.log("bird is alive");} else {UtilsKt.log("bird is destroyed");}};fun2.run();fun1.run();fun2.run();}}
用了和Kotlin完全一样的逻辑,编译期就报错了,IDEA提示我variable used in a lambda expression should be final or effectively final。
但是,给bird变量加上final之后,在fun1函数里面对bird=null的赋值语句就出错了,因为final引用是没办法二次赋值的。
所以Java里面的闭包,对外部变量只能读,不能写(但是可以修改这个外部变量的属性)。
4 总结
Kotlin的闭包设计更强大。
