直接上一段 Kotlin 的函数式编程的代码:
package com.easykotlin.lec02
fun sum1(x: Int, y: Int): Int {
return x + y
}
fun sum2(x: Int, y: Int) = x + y
// sum2 函数字面量: 匿名函数
val sum3 = fun(x: Int, y: Int) = x + y
val s3 = (fun(x: Int, y: Int) = x + y)(1, 1)
val s32 = (fun(x: Int, y: Int) = x + y).invoke(1, 1)
// Lambda
val sum4 = { x: Int, y: Int -> x + y }
val s4 = { x: Int, y: Int -> x + y }(1, 1)
val s42 = { x: Int, y: Int -> x + y }.invoke(1, 1)
val sum5: (Int, Int) -> Int = { x, y -> x + y }
// 高阶函数
fun repeat(n: Int, body: () -> Unit) {
for (i in 1..n) {
body()
}
}
// 类型别名
typealias A = (String) -> Int
typealias B = (Int) -> Boolean
typealias C = (String) -> Boolean
val length: A = { x -> x.length }
val isOdd: B = { x -> x % 2 == 1 }
// 高阶函数(复合函数)
val filterOdd: C = { x ->
isOdd(length(x))
}
fun main(args: Array) {
val list = listOf("a", "abc", "abcbdf", "adsfeeff", "qwedddsssssdd")
// 过滤出 list 中字符串长度是奇数的元素
val result = list.filter(filterOdd)
println(result)
repeat(3) {
println("A")
}
// 1 + 2 + 。。。 + 100
var sum = 0
var i = 1
repeat(100) {
sum += i
i++
}
println("sum = $sum")
sum1(1, 1)
sum2(1, 1)
sum3(1, 1)
sum4(1, 1)
sum5(1, 1)
println("s3 = $s3")
println("s32 = $s32")
println("s4 = $s4")
println("s42 = $s42")
}
Java 8:
public void filter(Filter f, List integerList) {
for (Integer i : integerList) {
if (f.test(i)) {
System.out.println(i);
}
}
}
// 定义一个 SAM
interface Filter {
boolean test(int x);
}
public void lambdaDemo() {
filter((x) -> x % 2 == 1, Arrays.asList(1, 2, 3, 4, 5, 6, 7));
}
Java 在一个拥有两个方法(不含默认方法)的接口中,是不可以使用 Lambda 表达式的,当一个接口中只有一个抽象方法,即达成了SAM(Single Abstract Method)条件时,Lambda表达式才可以使用。
Kotlin:
fun filter(f: (Int) -> Boolean, integerList: List) {
for (i in integerList) {
if (f(i)) {
println(i)
}
}
}
fun lambdaDemo() {
filter({ x -> x % 2 == 1 }, Arrays.asList(1, 2, 3, 4, 5, 6, 7))
}
在 Kotlin 中,函数 f:(Int)->Boolean 也是一种类型,可以像普通的参数变量一样,在函数入参中传递,当然也可以返回一个函数。
再举个例子:
fun repeat(times: Int, body: () -> Unit) {
for (i in 0 until times) {
body()
}
}
fun main(args: Array) {
repeat(3, {
println("A")
})
repeat(3) {
println("B")
}
var sum = 0
var i = 1
repeat(100) {
sum += i
i++
}
println(sum)
}
Function 接口
函数 Function 接口类型只有一个调用方法:invoke() 。
它包含三个动作:传入参数、处理参数、返回结果。
Kotlin定义了kotlin.Function
关键在于:kotlin.jvm.functions包里定义了
package kotlin.jvm.functions
/** A function that takes 0 arguments. */
public interface Function0 : Function {
/** Invokes the function. */
public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1 : Function {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2): R
}
/** A function that takes 3 arguments. */
public interface Function3 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3): R
}
/** A function that takes 4 arguments. */
public interface Function4 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4): R
}
/** A function that takes 5 arguments. */
public interface Function5 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5): R
}
/** A function that takes 6 arguments. */
public interface Function6 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6): R
}
/** A function that takes 7 arguments. */
public interface Function7 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7): R
}
/** A function that takes 8 arguments. */
public interface Function8 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8): R
}
/** A function that takes 9 arguments. */
public interface Function9 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9): R
}
/** A function that takes 10 arguments. */
public interface Function10 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10): R
}
/** A function that takes 11 arguments. */
public interface Function11 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11): R
}
/** A function that takes 12 arguments. */
public interface Function12 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12): R
}
/** A function that takes 13 arguments. */
public interface Function13 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13): R
}
/** A function that takes 14 arguments. */
public interface Function14 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14): R
}
/** A function that takes 15 arguments. */
public interface Function15 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15): R
}
/** A function that takes 16 arguments. */
public interface Function16 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16): R
}
/** A function that takes 17 arguments. */
public interface Function17 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17): R
}
/** A function that takes 18 arguments. */
public interface Function18 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18): R
}
/** A function that takes 19 arguments. */
public interface Function19 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19): R
}
/** A function that takes 20 arguments. */
public interface Function20 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20): R
}
/** A function that takes 21 arguments. */
public interface Function21 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21): R
}
/** A function that takes 22 arguments. */
public interface Function22 : Function {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21, p22: P22): R
}
来分别抽象无参到22个参数的函数,它们都继承了kotlin.Function接口,同时定义了一个invoke()函数。
大于22个参数的函数,使用 FunctionN 接口:
package kotlin.jvm.functions
import kotlin.jvm.internal.FunctionBase
/**
* A function that takes N >= 23 arguments.
*
* This interface must only be used in Java sources to reference a Kotlin function type with more than 22 arguments.
*/
@SinceKotlin("1.3")
interface FunctionN : Function, FunctionBase {
/**
* Invokes the function with the specified arguments.
*
* Must **throw exception** if the length of passed [args] is not equal to the parameter count returned by [arity].
*
* @param args arguments to the function
*/
operator fun invoke(vararg args: Any?): R
/**
* Returns the number of arguments that must be passed to this function.
*/
override val arity: Int
}
如下是Function2接口:
interface Function2 : Function {
operator fun invoke(p1: P1, p2: P2): R
}
p1和p2是传入的两个参数类型,R就是返回值类型。因为我们只会向函数传入参数、从函数中取出返回值,所以分别用in和out修饰。
invoke()函数定义了“调用”这个行为,它同时重载了括号操作符,允许用括号来传入参数、得到返回值。
我们可以定义一个匿名函数,然后把它赋值给sum变量:
val sum: (Int, Int) -> Int = fun(a: Int, b: Int) = a + b
由于匿名函数已经定义好参数列表和返回值类型了,我们可以省略sum的类型声明:
val sum = fun(a: Int, b: Int) = a + b
Lambda表达式就是一个匿名函数,可以把这个匿名函数改写为Lambda表达式:
val sum = { a: Int, b: Int -> a + b }
上面定义的sum函数对象,它会被编译为一个Function2类型的对象,(Int,Int)->Int是Function2接口的具体实现类,可以使用invoke()函数来调用它:
println(sum.invoke(1,2))
也可以直接用括号操作符:
println(sum(1,2))
小结
相比之下,Kotlin 对函数式编程的支持更加自然优雅。
Kotlin 开发者社区
国内第一Kotlin 开发者社区公众号,主要分享、交流 Kotlin 编程语言、Spring Boot、Android、React.js/Node.js、函数式编程、编程思想等相关主题。