lambda 表达式( lambda expressions):一段可以传递给其他函数的代码块
高阶函数(high-order-functions):可以接受其他函数作为参数的就是高阶函数
函数式编程(functional programming):一个编程形式,支持函数作为一个普通类型的编程方式。函数可以作为变量,参数。
函数式接口(functional interface):内部只有一个方法的接口。Java 8 的 lambda 只支持这类函数写法。
SAM(signle abstract method):函数式接口的一种叫法,只有一个抽象方法。比如一个方法的接口,一个抽象方法的类。
纯函数(pure function):函数式编程中的一个概念,如果函数不依赖函数外部的变量,那么函数就是纯函数,就是后面说的not capturing
。反之就是capturing
。
在 Java 8 之前通过匿名内部类的方式实现接口回调
1 | button.setOnTouchListener(new View.OnTouchListener() { |
Java 8 中的 lambda 写法
1 | button.setOnTouchListener((v, event) -> false); |
Define and use
kotlin 中的 lambda 于Java lambda 类似。由{}
包裹起来,参数不需要()
1 | { param1 : Type1, param2 : Type2 -> body } |
- 最外部是一个大括号,大括号包裹者代码。
- 左边是参数,不需要括号,由
->
区分开 - 右边是函数体
body
。如果由返回值用return@<operation>
对于 lambda 的调用方式。可以直接向普通函数一样调用,也可以通过invoke()
方法调用,也可以直接的运行,只不过这样可读性不是很好。
1 | val addOffset = { x: Int -> x + 1 } |
当 lambda 是函数的最后一个参数时,写法上可以变动下,可以直接写在外部
1 | fun addOffset(init: Int, block: (Int) -> Int): Int = block(init) |
由于类型可以被推断,所以可以省略参数的类型
1 | addOffset(1) { x -> x + 1 } |
如果参数没有使用,可以用_
符号省略
1 | addOffset(1) { _ -> 1 } |
如果 lambda 的参数只有一个,参数也可以省略,使用it
来访问
1 | addOffset(1) { it + 1 } |
Differences of Java and Kotlin Lambda
Java 中 lambda 访问外部变量必须为final
。
Kotlin 中没有这个限制,外部被访问到的变量被翻译成Ref
类型,可以传递修改变量。Local Function 中可以看见
Compatibity with Java Functional Interface
Kotlin 中的 lambda 完全兼容 Java 中的 Functional Interface。
Auto Convert
兼容方式一,通常编译器能够将 lambda 表达式自动转换成匿名内部类来实现 Functional Interface 。
- 对于
capturing
的函数,Functional Interface 被编译成一个匿名内部类的实列 - 对于
not capturing
的函数,Functional Interface 被编译成一个的实列(单列),在每个地方使用
1 | // 访问了外部的 view |
查看编译的 Java 代码
1 | public static final void testCapturing(@NotNull Context context) { |
SAM Constructor
兼容方式二,有时候需要使用 SAM Constructor 可以将lambda 表达式转换成 Functional Interface 的实列。
SAM Constructor 语法
1 | FunctionalInterfaceName { lambda_function } |
以下情况:
1 | // 赋值给变量 |
请注意,SAM 转换只适用于接口,而不适用于抽象类,即使这些抽象类也只有一个抽象方法。
还要注意,此功能只适用于 Java 互操作;因为 Kotlin 具有合适的函数类型,所以不需要将函数自动转换为 Kotlin 接口的实现,因此不受支持。
Java SAM vs. Kotlin Function Type
Kotlin uses function types instead of interfaces.So if you are coding in pure Kotlin, it is important to use function types for lambda types as Kotlin does not support conversion of lambdas to Kotlin interfaces
在 kotlin 中 function types 定义了函数的规则,只要满足了这种规则的函数都是这一类函数。比如()->Unit
是一个 function type,它描述了这样一类函数,不需要参数,返回值是 Void 的类型,比如Runnable
接口就符合这种规则。
function type 定义的函数可以通过 SAM Constructor 方式转换成 Java 接口的实现。
function type 不能转换成 kotlin 中的接口实现,所以在定义 lambda 的时候用 function type,可以做更多的兼容。
other
简洁的 concise
Lambda expressions represents these functional interfaces in a more concise way to deal with functional programming
推断 inferred
If the function has a single argument and its type can be inferred, an autogenerated variable named it will be available for you to use
解释 interprets
The compiler interprets a lambda function that represents a functional interface as a instance of an anonymous class implementing that functional interface
参考
kotlinDoc-lambdas
kotlinDoc-sam conversions
Idiomatic Kotlin: lambda and sam constructors