Kotlin高级特性:4、作用域函数与常用操作符

一、Kotlin的作用域函数

  • run {…}
  • with(T){…}
  • let{…}
  • apply{…}
  • also{…}

作用域函数是Kotlin内置的一系列可以对数据做一些变换的函数,与集合的操作符很相似,但集合的操作符只能作用域集合对象,而作用域函数可以操作任何对象。

二、代码实现

package zyf.kotlin

fun main(args: Array<String>) {

    val user = User("zyf")

    /**
     * let与run都会返回闭包的执行结果
     * 不同:
     *      let有闭包参数,run没有闭包参数
     *      let的闭包参数就是调用者本身,参数名为it
     *      run没有闭包参数,可以使用this指代调用者
     * 注:在let中,不可以使用this指代调用者
     */
    val letResult = user.let {
        "let::${it.javaClass}"
    }
    println(letResult)

    val runResult = user.run {
        "run::${this.javaClass}"
    }
    println(runResult)

    /**
     * also与apply都不返回闭包的执行结果
     * also和apply都会返回调用者本身,所以可以使用链式调用
     * 不同:
     *      also有闭包参数,apply没有闭包参数
     *      it与this的区别与let,run类似
     */
    user.also {
        println("also::${it.javaClass}")
    }

    user.apply {
        println("apply::${this.javaClass}")
    }

    /**
     * takeIf的闭包会返回一个判断结果,为false时,takeIf函数会返回空
     *      如果判断为true,则会返回调用者本身,可以继续链式调用
     * takeUnless 与 takeIf刚好相反,闭包的判断结果,为true时函数会返回空
     *
     */
    user.takeIf {
        //判断长度是否大于0
        it.name.isNotEmpty()
    //这里使用?.判断 takeIf 的返回值是否为空,如果为空,就不会执行also
    // 使用 ?: 判断是否为空,如果为空,则执行后面的语句
    }?.also {
        println("姓名为${it.name}")


    }?: println("姓名为空")


    user.takeUnless { it.name.isNotEmpty() }?.also { println("姓名为空") }?: println(user.name)

    //重复执行当前闭包
    repeat(5){
        print(it)
        println(user.name)
    }

    //with比较特殊,上述的作用域函数,都是以扩展函数的形式,扩展到对象上的
    //with不是扩展函数,而是一个顶级函数
    //with接受两个参数,一个是with要作用的对象(这里就是user)
    //另一个就是{}  接受一个闭包
    //那么实际上,是user去执行了闭包里的内容

    //在安卓中通常用于设置一些view的属性
    with(user){
        this.name = "with"
    }
    println(user.name)

    //上述,可以简单理解为以下代码
//    user.apply { this.name = "with" }
}

三、常用操作符

1,元素操作类

元素操作类含义
contains判断是否有指定元素
elementAt返回对应的元素,越界会抛 IndexOutOfBoundsException
firstOrNull返回符合条件的第一个元素,没有则返回 null
lastOrNull返回符合条件的最后一个元素,没有则返回 null
indexOf返回指定元素的下标,没有则返回 -1
singleOrNull返回符合条件的单个元素,如果没有或超过一个,则返回 null
package zyf.kotlin

fun main(args: Array<String>) {
//    元素操作类
    val names = arrayOf("孙悟空","猪八戒","唐僧","沙和尚","白龙马","玉帝","王母娘娘","太白金星","太上老君","二郎神杨戬")

    val contains = names.contains("孙悟空")
    println("是否含有:$contains")

    val elementAt = names.elementAt(2)
    println("下标为2的元素是:$elementAt")

    val firstOrNull = names.firstOrNull {
        it.length == 2
    }
    println("符合长度是2的第一个元素是:$firstOrNull")

    val lastOrNull = names.lastOrNull {
        it.startsWith("太")
    }
    println("最后一个以'太'结尾的元素是:$lastOrNull")

    val indexOf = names.indexOf("二郎神杨戬")
    println("二郎神杨戬的下标为:$indexOf")

    val singleOrNull = names.singleOrNull {
        it.length == 5
    }
    println("长度为5的元素是:$singleOrNull")

    val singleOrNull1 = names.singleOrNull {
        it.length >= 2
    }
    //这里会输出null,因为大于等于2的元素数量大于1
    //singleOrNull 操作符就会返回 null
    println("长度大于等于2的元素是:$singleOrNull1")
}

2,判断类

判断类含义
any判断集合中是否有满足条件的元素
all判断集合中的元素,是否都满足条件
none判断集合中是否都不满足条件,是则返回true
count查询集合中,满足条件的元素个数
reduce从第一项到最后一项进行累计
package zyf.kotlin

fun main(args: Array<String>) {
    //判断类
    val users = listOf(User("伏天氏"),User("飞剑问道"),User("大道朝天"))

    val any = users.any {
        it.name.length == 5
    }
    //any 只要有一个就能满足,一个没有就返回null
    println("用户名字长度等于5的是:$any")

    val all = users.all {
        it.javaClass == User::class.java
    }
    println("元素类型是否都为User::class.java:$all")

    val none = users.none {
        it.name.length >= 3
    }
    println("集合中的元素的name长度是否都不大于等于3:$none")

    val count = users.count {
        it.name.length >= 3
    }
    println("集合中的元素的name长度大于等于3的数量为$count")


    val demo = mutableListOf("张","李","周","郑")
    val reduce = demo.reduce { acc, s ->
        acc + s
    }
    println("从第一项累加到最后一项的结果为:$reduce")
}

3,过滤类

过滤类含义
filter过滤掉所有满足条件的元素
filterNot过滤掉所有不满足条件的元素
filterNotNull过滤NULL
take返回前n个元素
package zyf.kotlin

fun main(args: Array<String>) {

    val age = mutableListOf(1,2,3,4,5,6,7)

    age.filter {
        it>3
    }.also {
        println("过滤掉大于3的值后:$it")
    }

    age.filterNot {
        it>3
    }.apply {
        println("过滤掉所有不满足大于3的值后(剩下的应该都是小于等于3的):$this")
    }

    val genders = listOf("男",null,"女")
    val let = genders.filterNotNull().let { it[1] }
    println("过滤掉NULL元素后,下标为1的元素是:$let")

    val take = age.take(3)
    println("前三个元素是:$take")
}

4,转换类

转换类含义
map转换成另一个集合(与前面的 convert 方法作用一样
mapIndexed除了转换成另一个集合,还可以拿到 Index
mapNotNull执行转换后,过滤掉为 NULL 的元素
flatMap自定义逻辑合并两个集合
groupBy按照某个条件分组,返回 Map
package zyf.kotlin

fun main(args: Array<String>) {

    val loc = listOf("北京", "上海", "广州", "深圳", "杭州")
    loc.map {
        //使用map函数,将每个元素+你好生成一个新的集合
        "$it 你好"
    }.also {
        //输出新集合
        println(it)
    }

    loc.mapIndexed { index, s ->
        "这是第$index 个元素:$s"
    }.also {
        //上面的一整个字符串,就是新集合的一个元素
        println(it)
    }

    val loc2 = listOf(null, "北京", "上海", "广州", "深圳", "杭州")

    /**
     * 经测试,并不是在转换前判断null
     * 而是判断转换后的结果,结果为null,则被移除
     */
    val mapNotNull = loc2.mapNotNull {
        it
    }
    println("转换后的结果里有null,那么这个null就被移除了:$mapNotNull")
    /**
     * 所以下面的代码,依然会看到null
     */
    val mapNotNull1 = loc2.mapNotNull {
        it + 1
    }
    println("转换后的结果中没有null,只有[null1],并不会被移除:$mapNotNull1")


    /**
     * 在源码中,先创建一个空集合
     * 然后遍历调用者(loc)
     * 每次遍历,会将loc中的元素传入到闭包中(就是it)
     * 然后将闭包的返回结果( listOf(it, it + 1)
     * 添加到前面建立的新集合中
     * 最后的结果就是:
     *
     * [listOf(it, it + 1),listOf(it, it + 1),listOf(it, it + 1),listOf(it, it + 1)...]
     * it是loc遍历的元素,是从loc的第0位,一直遍历到底 loc.length-1 位的
     */
    val flatMap = loc.flatMap {
        listOf(it, it + 1)
    }
    println("转换后的结果:$flatMap")

    /**
     * 根据条件对集合中的元素进行分组,返回map
     * 因为返回的是一个map,自然就需要指定key
     * 下面语句1,就是在指定key
     * 语句2,未指定key,则默认是true或false为key
     *
     */
    val groupBy = loc2.groupBy {
//   1     if(it==null)"even" else "old"
//   2     it.isNullOrBlank()
    }
    println(groupBy)

}

关于 flatMap 操作符的源码分析


5,排序类

排序类含义
reversed倒序
sorted升序
sortedBy自定义升序
sortedDescending降序
sortedByDescending自定义降序
package zyf.kotlin

fun main(args: Array<String>) {

    val projects = listOf("语文","数学","外语","物理","化学","生物","政","历","地")

    //倒序
    val reversed = projects.reversed()
    println("倒序:$reversed")

    //升序,暂时没研究是按照什么逻辑进行排序的
    val sorted = projects.sorted()
    println("升序:$sorted")

    val sortedBy = projects.sortedBy {
        it.length
    }
    println("自定义排升序:$sortedBy")

    val sortedDescending = projects.sortedDescending()
    println("降序:$sortedDescending")

    val sortedByDescending = projects.sortedByDescending {
        it.length
    }
    println("自定义降序:$sortedByDescending")
}

版权声明:本文为android_zyf原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。