Kotlin Lambda 表达式基础

122 阅读2分钟

一、基础语法结构

val sum: (Int, Int) -> Int = { a, b -> a + b }
println(sum(3,5)) // 输出 8 :ml-citation{ref="7" data="citationList"}
  • 组成要素‌:

    • 参数列表:(a, b) 或省略括号的单参数 it
    • 箭头符号:->(不可省略)
    • 函数体:最后一行作为返回值 68
  • 类型声明方式‌:

    kotlinCopy Code
    // 完整声明
    val greet: (String) -> Unit = { name -> println("Hello $name") }
    
    // 类型推断简写
    val square = { x: Int -> x * x } :ml-citation{ref="6,7" data="citationList"}
    

二、与Java函数 对比

//1.函数声明  用Lambda 表达式
val method01 : () -> Unit
//public void method01()
val method02 : (Int,Int) -> Unit
//public void method02(int int1,int int2)
val method03 : (String,Double) -> Any
//public Object method03(String str,Double dou)
var method04 : (Int,Double,Long,String) -> Boolean
//public Boolean method04(int x1,double x2,long x3,String x4)
var method05 : (Int,Int) -> Int
//public int method5(int x1,int x2)

三、案例解析

  val method1:()-> Unit = { println("我是method1 函数")}
//    val method1 = { println("我是method1 函数")}
    method1()         //调用函数 ()== 操作符重载,invoke操作符
    method1.invoke()  //调用函数

//    val method2:(Int,Int)->Unit= {x,y -> println("我是method2函数 参数1$x,参数2$y")}
    val method2 = {x:Int,y:Int -> println("我是method2函数 参数1$x,参数2$y")}
    method2(1,2)
    method2.invoke(1,2)

//    val method3 : (String,Double) -> Any = {x,y -> "你传递的值分别是 $x 与 $y"}
    val method3  = {x:String,y:Double -> "你传递的值分别是 $x$y"}
    println(method3.invoke("你好",4.0))

//    val method4 : (number1:Int,number2:Int) -> String = {number1,number2 -> number1.toString() + number2.toString()}
    val method4 = {number1:Int,number2:Int ->number1.toString() + number2.toString() }
    println(method4.invoke(1,2))


//    var method5 : (Int,Int) -> Int = {x,y -> x+y}
    var method5  = {x:Int,y:Int -> x+y}
    println(method5(1,3))

    //先声明 后实现
    val method6:(Int,Int) -> Int     //先声明
    method6 = fun(x:Int,y:Int):Int = x + y
    println(method6(1,3))

    //先声明 后实现 类型推断
    val method7:(Int) -> String
    method7 = fun(num:Int):String = num.toString()
    println(method7(88))

    //声明 实现一气呵成

    val method8: (Int) -> String/**左边是声明**/  /***右边是实现***/ = {x -> x.toString()}
    println(method8(99))

    val method9:(String,String) ->Unit = {str1,str2 -> println("传入参数1$str1,传入参数$str2")}
    method9.invoke("AA","BB")

    //只有一个参数时候,如果你不写,就会默认有一个it替代,会自动添加,两个或多个时就没有
    val method10:(String) ->Unit = {
        println("只有一个参数 默认it $it")
    }

    val method11:(Int) ->Unit = {
        when(it){
            1 -> println("你传递进来的是一")
           in 10..20 -> println("你传递进来的是10到20之间的数字")
            else -> println("你传递的数字不满")
        }
    }

    method11.invoke(15)


    // _ 拒收,可以提高一点性能
    val method12:(Int,Int) ->Unit = {_,x -> println("传递的第二个参数是$x")}
    method12.invoke(100,101)

    //(Any) -> Any
    val method13 = {str:Any -> str}
    println(method13.invoke(true))
    println(method13.invoke(14.556))

    //(Char) ->Unit
    val method14 = { char:Char ->
        if (char.equals('男')) "这是一名男士" else if (char.equals('女')) "这是一名女士"
        else "这是未知"
    }

    println(method14.invoke('男'))
    println(method14.invoke('好'))

    //(Int) ->Unit

    var method15 = {x:Int -> println("你传递的值$x")}
    //覆盖了 method15 ,但是还是(Int) ->Unit
    method15 = {println("覆盖的也能拿到值:$it")}  //这里注意一点是  覆盖的时候前面不能有声明符号了

    method15.invoke(55)

    // ? 可传null
    var method16 = {str1:String?,str2:String -> println("参数$str1,参数2$str2")}
    method16.invoke("张飞","赵云")
    method16.invoke(null,"赵云")

    //需求:你传递什么我打印什么
    // (Any) -> Any
    val method17 = {x:Any -> println("传递啥输出啥值:$x")}
    method17.invoke(111)
    method17.invoke(3.1415)
    method17.invoke("hello")
    
    
val method19:String.() -> Unit = {
    println("你是$this")
}
  "DDD".method19()

  //两数相加结果  这里有主意一点是 ${} Kotlin 中的 ${} 是字符串模板的核心语法,用于在字符串中嵌入变量或表达式
  val method20:Int.(Int) -> Unit = {
      println("两数相加结果:${this+it}")
  }
  2.method20(2)
  //三数相加结果
  val method21:Double.(Double,Double) -> Unit = {
      d1,d2 ->
      println("3数相加结果:${this +d1 +d2}")
  }
  4.5.method21(3.0,5.0)

  //(Char) -> String
  val method22: Char.(String) ->String = {
      if (this =='男')  "这是一名男士" else if (this =='女') "这是一名女士"
      else it
  }

  println('男'.method22("未知"))
  println('A'.method22("未知"))

 fun Char.method23(default: String):String{
     return if (this =='男')  "这是一名男士" else if (this =='女') "这是一名女士"
     else "未知"
 }

  println('男'.method23("未知"))
  println('A'.method23("未知"))

四、特殊使用技巧

  1. 带接收者的 Lambda‌:

    kotlinCopy Code
    val buildString: StringBuilder.() -> Unit = {
        append("Hello")
        append(" World")
    }
    
    val sb = StringBuilder()
    sb.buildString()
    println(sb) // 输出 "Hello World" :ml-citation{ref="8" data="citationList"}
    
  2. 空安全调用‌:

    kotlinCopy Code
    val nullableStr: String? = null
    nullableStr?.let { 
        println(it.length) // 安全执行,不会触发 NPE :ml-citation{ref="7" data="citationList"}
    }
    
  3. 集合操作链‌:

    kotlinCopy Code
    val result = (1..10)
        .filter { it % 3 == 0 }
        .map { it * 2 }
        .takeIf { it.size > 2 } ?: emptyList() :ml-citation{ref="7,8" data="citationList"}
    

五、性能优化要点

场景推荐方案说明
频繁调用的 Lambda使用 inline 关键字修饰高阶函数避免生成匿名类,减少内存开销 8
长Lambda链使用序列(asSequence()延迟计算提升性能
多参数场景使用具名参数提高代码可读性

六、与 Java 交互对比

特性Kotlin LambdaJava Lambda
SAM 转换自动支持(适用 Java 接口)需要函数式接口注解
空安全处理支持空安全调用符 ?.需要显式 null 检查
闭包变量修改允许修改非 final 变量只能访问 final/有效 final 变量

通过合理使用 Lambda 表达式,可使代码更简洁高效。建议优先在集合操作、回调处理、DSL 构建等场景中使用,但需注意避免过度嵌套导致的代码可读性下降