我就不加目录了,也不会涉及很多代码,就根据我个人的理解简单聊聊,算是给未来健忘的自己写个小tip。

这个寄吧lambda表达式,我当初学Java的时候就没怎么学明白,到了Kotlin更是一头雾水。

今天下午的时候,看着看着就有些悟了。

首先明确几个规定:

  • Kotlin函数的参数可以是一个函数体(lambda表达式);
  • 当函数体参数是最后一个参数的时候,可以将函数体从括号中移出去;
  • 当被调用的函数只有一个参数且该参数是函数体参数时,括号可以省略。

函数体作为参数传给另一个函数?为什么要这么设计?
其实,这个设计不是为了方便被调用的函数,而是为了方便我们自己。通过这个函数体参数,被调用的函数得到了什么?其实只得到了“返回值”,那既然他只需要返回值,那我们为什么不在外面将这个函数体参数定义完整,然后再使用一个变量接收返回值传给被调用函数呢?
傻逼吧,刚刚已经说了这是为了方便我们自己,看一下这种情况:

    val list = listOf("123","12345","1","45","456106","635","51575")
    var maxLenStr = ""
    for (str in list){
        if(str.length > maxLenStr.length){
            maxLenStr = str
        }
    }

仅仅是为了获得最长的字符串就要这么麻烦,再看看下面这种形式:

    val list = listOf("123","12345","1","45","456106","635","51575")
    val maxLenStr = list.maxByOrNull { it.length }

这就很方便了,那么究竟是怎么回事呢?追进去看一下:

public inline fun <T, R : Comparable<R>> Iterable<T>.maxByOrNull(selector: (T) -> R): T? {
    val iterator = iterator()
    if (!iterator.hasNext()) return null
    var maxElem = iterator.next()
    if (!iterator.hasNext()) return maxElem
    var maxValue = selector(maxElem)
    do {
        val e = iterator.next()
        val v = selector(e)
        if (maxValue < v) {
            maxElem = e
            maxValue = v
        }
    } while (iterator.hasNext())
    return maxElem
}

可以看到,我们传入的函数体被当成了一个函数,名为selector,这个函数接收it为参数,并返回it.length

it是什么呢?其实就是list本身,将函数调用者自身传入函数中作为参数,这也是Kotlin的强大之处。

可以看到,maxByOrNull函数的实际作用就是先判断list是否为空,如果是空就直接返回空,然后判断是否只有一个元素,如果是的话就直接返回这一个。不止一个的话就不断迭代判断。

相当于Kotlin将这些可能存在的繁琐语句都包装实现了。

所以回顾一下我刚开始说的,被调用的函数实际上只是需要函数体参数的返回值,我们可以将他视作一种条件,可以抽象出以下模型:

  • 函数还是原本的作用:接收输入→处理→提供输出;
  • lambda相当于一个协助函数工作的小工具,以自己的返回值协助函数完成相关功能。

在上面这个例子中,

  • 函数作用是根据某种条件选出使该条件值最大的一个元素;
  • lambda的返回值告诉函数:条件是元素的字符串长度

那有的人又要问了:这不就是封装了一个函数么?那我用Java封装一个函数不也是一样的效果?
所以说呢,学而不思则罔。
注意我前面说的,lambda以自己的返回值协助函数完成相关功能。这也就是说,返回值是关键,我们无论提供什么返回值,该函数都能利用它来最终返回最大的一个元素。
那我们是不是漏了什么东西?没错,lambda只有返回值吗?显然不是啊,函数只是需要lambda的返回值而已,没有强制lambda除了返回值外不能有其他的语句,所以我们可以针对性地定制对元素的操作,这是封装函数所做不了的,举个例子:
我们想要在寻找最长字符串的时候,看一下每一个元素究竟是多长:

    val list = listOf("123","12345","1","45","456106","635","51575")
    val maxLenStr = list.maxByOrNull {
        println(it.length)
        it.length
    }
    println(maxLenStr)

也就是说,相较于封装成函数,使用lambda的方式是可以对函数高度定制的。

这就使得开发者可以写出功能更加丰富的应用了。

更多推荐