kotlin高级特性

作者: 奔跑吧李博 | 来源:发表于2020-09-11 14:32 被阅读0次

Kotlin语法的高级特性异常强大,代码异常简洁,如果你在项目中能熟练使用各种kotlin高级特性后,你会发现,你之前这些年写的代码都是在浪费生命。

标准函数

kotlin的标准函数,指的是Standard.kt文件中定义的函数,包括let、also、with、run、apply函数。

  • let函数

let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择;let函数另一个作用就是可以避免写一些判断null的操作。

适用场景
场景一: 最常用的场景就是使用let函数处理需要针对一个可null的对象统一做判空处理。

        //没有let函数,需要每次判空,代码不够优雅
         data?.toString()
        data?.toString()
        data?.toString()

data?.let {
            //在函数域中,保证data对象不为,不用多次去判空
            it.toString()
            it.toString()
            it.toString()
        }

场景二: 然后就是需要去明确一个变量所处特定的作用域范围内可以使用

data.let {
            //在函数体内使用it替代该data对象使用
            it.toString()
        }
also函数

also函数使用的一般结构

object.also{

}

适用于let函数的任何场景,also函数和let很像,只是唯一的不同点就是let函数最后的返回值是最后一行的返回值而also函数的返回值是返回当前的这个对象。

        user?.also {
            it.age = 18
            it.name = "小明"
        }.age
with函数

with函数使用的一般结构

with(object){
   //todo
 }

它是将某对象作为函数的参数,在函数块内可以通过 this 指代该对象。

适用场景
需要设置某个对象多个属性到UI上时,需要不断调用对象,使用with函数能避免对象的重复书写。

        data class User(var name: String, var age: Int)

        with(user){
            Log.i("TAG", "age=$age")
            Log.i("TAG", "name=$name")
        }

该age和name变量就是该with参数中的user对象的属性值。

run函数

run函数使用的一般结构

object.run{
    
}

适用场景
适用于let,with函数任何场景。因为run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理。

        user?.run {
            Log.i("TAG", "age=$age")
            Log.i("TAG", "name=$name")
        }
apply函数

apply函数使用的一般结构

object.apply{

}

从结构上来看apply函数和run函数很像,唯一不同点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply可以任意调用该对象的任意方法,并返回该对象。

适用场景
整体作用功能和run函数很像,唯一不同点就是它返回的值是对象本身,而run函数是一个闭包形式返回,返回的是最后一行的值。

场景一:apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。

data class User(var name: String, var age: Int)

ArrayList<User>().apply {
            add(User("小明", 18))
            add(User("小王", 16))

        }.run {
            get(0)
        }       

创建User对象并添加入集合,添加完成后取出第一个对象。

场景二:多层级判空问题

    data class Response(var code: Int, var data: Data)

    data class Data(var icon: String, var title: String)

        response?.apply {
            //response不为空时可操作response
            
        }.data?.apply {
            //data不为空时可操作data
            
        }.title?.apply {
            //title不为空时可操作title
            
        }
let,with,run,apply,also函数总结:
函数名 函数体内使用的对象 返回值 适用场景
let it指代当前对象 闭包形式返回 适用于处理多处判空的场景
also it指代当前对象 返回this 适用于let函数的任何场景,一般可用于多个扩展函数链式调用
with this指代当前对象或者省略 闭包形式返回 适用于调用同一个类的多个方法、属性时,省去每次书写类名
run this指代当前对象或者省略 闭包形式返回 适用于let,with函数任何场景
apply this指代当前对象或者省略 返回this 适用于run函数任何场景,一般可用于多个扩展函数链式调用
takeIf,takeUnless函数
        user.name.takeIf {
            TextUtils.isEmpty(it)
        }.let {
            print(it)
        }

        user.name.takeUnless {
            !TextUtils.isEmpty(it)
        }.let {
            print(it)
        }

takeIf的闭包返回一个判断结果,如果为false时takeIf函数返回null;takeUnless与takeIf相反,为true时takeUnless函数返回null。

使用场景:只需要单个if分支语句的时候
优点:
可以配合其他作用域函数返回的结果,做出单向判断,保持链式调用
简化写法,逻辑清晰,减少代码量,代码更优雅

委托

委托是软件设计的一种模式,当无法或不想访问某个对象或访问某个对象存在困难时,可以交给委托类来处理。

  • 类委托:即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。
interface User {
    fun login()
}

class UserImpl(val name: String) : User{
    override fun login() {
        println(name)
    }
}

class VipUser(user: User) : User by user

fun main() {
    VipUser(UserImpl("1号用户")).login()
}

可以看到委托类并没有实现User接口,而是通过关键字by,将实现委托给了user。

  • 属性委托:指的是一个类的某个属性值不是在类中直接定义,而是将其委托给一个代理类,从而实现对该类属性的统一管理。
扩展函数

扩展函数表示即使在不修改某个类的源码的情况下,我们仍然可以对某个类添加方法,进行扩展。例如我们对User类增加登录的功能,实现在类外面添加方法。

    fun User.login() {
        Log.i("TAG","去登录")
    }

 data class User(var name: String, var age: Int)

扩展了login方法,就可以使用user.login()。可以看到,扩展函数的主要写法就是在定义方法名的时候,通过Class.直接声明是在哪个类中。

集合操作符

Kotlin中可以通过集合操作符直接对集合进行操作,从而得到想要的结果。

map:对集合中的数据做改变,可以改变数据的类型。
filter:得到所有符合Lambda闭包中操作的数据。
find:得到符合Lambda闭包中操作的第一个数据。
findLast:得到符合Lambda闭包中操作的最后一个数据。
reduce:含有两个参数(集合中相邻的两个参数,用于遍历整个集合),对这两个参数进行操作,返回一个新参数,要求类型与集合中的参数类型相同。

协变与逆变

我们约定,在一个泛型类或者泛型接口的方法中,它的参数列表是接收数据的地方,就称为in位置,他的返回值是输出数据的地方,就称为out位置。

fun <T>test(param: T):T {
    return param
}

如上test方法中,传入泛型T的位置为in位置,返回类型T的位置为out位置。

泛型的协变:假如定义了一个MyClass<T>的泛型类,其中A是B的子类型,同时MyClass<A>又是MyClass<B>的子类型,我们就可以称MyClass在T这个泛型是协变的。如果泛型都是只读的(泛型加上out关键字),就能实现MyClass<A>是MyClass<B>的子类型
泛型的逆变:假如定义了一个MyClass<T>的泛型类,其中A是B的子类型,同时MyClass<B>又是MyClass<A>的子类型,我们就可以称MyClass在T这个泛型是逆变的。如果泛型都是只写的(泛型加上in关键字),就能实现MyClass<B>是MyClass<A>的子类型

高阶函数

如果一个函数接收另一个函数作为参数,或者返回类型是一个函数,那么这个函数我们就称之为高阶函数。
简单用例:

class Gaojie {
    fun main() {
        calculate(10, 5, ::add)
    }
}

/**
 * 加法
 */
fun add(a: Int, b: Int): Int {
    return a+b
}

/**
 * 减法
 */
fun minus(a: Int, b: Int): Int {
    return a-b
}

/**
 * 运算
 *
 * operate:(Int, Int)->Int 表示定义的一个函数,将其作为calculate参数的形参,实际传的时候是传入add或minus函数
 */
fun calculate(a:Int, b:Int, operate:(Int, Int)->Int) {
    var result = operate(a,b)
    print("操作结果为 $result")
}

首先定义了一个高阶函数,他传入三个参数,两个Int型的值和一个函数类型的值,在方法内部调用“函数类型的值”,因为它本身是函数,所以可以直接调用,并且将前两个Int型作为形参传了进去。接下来我们定义了两个函数add和minus,这两个函数实现他们本身的逻辑,最后在main函数里面调用了此高阶函数,其中::add和::minus是固定写法,表示函数的引用。

协程

协程通过将复杂性放入库来简化异步编程。程序的逻辑可以在协程中顺序地表达,而底层库会为我们解决其异步性。该库可以将用户代码的相关部分包装为回调、订阅相关事件、在不同线程(甚至不同机器)上调度执行,而代码则保持如同顺序执行一样简单。

DSL(domain specific language)

即领域专用语言:专门解决某一特定问题的计算机语言,比如大家耳熟能详的 SQL 和正则表达式。

通用编程语言 vs DSL
通用编程语言(如 Java、Kotlin、Android等),往往提供了全面的库来帮助开发者开发完整的应用程序,而 DSL 只专注于某个领域,比如 SQL 仅支持数据库的相关处理,而正则表达式只用来检索和替换文本,我们无法用 SQL 或者正则表达式来开发一个完整的应用。

参考

Kotlin系列之let、with、run、apply、also函数的使用
Kotlin协程
Kotlin之美——DSL篇
一篇文章搞定kotlin

相关文章

  • kotlin高级特性

    Kotlin语法的高级特性异常强大,代码异常简洁,如果你在项目中能熟练使用各种kotlin高级特性后,你会发现,你...

  • Kotlin高级特性

    委托 委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托...

  • kotlin - 高级特性

    kotlin 上手很简单,因为可以完美支持 java ,和 java 比较像的缘故,我们熟悉下 kotlin 的语...

  • Kotlin 中的 let, with, run, apply,

    前言 和严格古老的 Java 相比,Kotlin 中额外提供了不少高级语法特性。这些高级特性中,定义于 Kotli...

  • kotlin的内联函数的使用

    kotlin的内联函数属于kotlin的高级特性了,也是不同于java的区别之一;至于为什么kotlin要使用内联...

  • Kotlin高级特性(二)

    一、集合操作符 Kotlin中可以通过集合操作符直接对集合进行操作,从而得到想要的结果。 map:对集合中的数据做...

  • Kotlin-简约之美-进阶篇(十五):let、with、run

    @[toc]相比Java, Kotlin提供了不少高级语法特性。对于一个Kotlin的初学者来说经常会写出一些不够...

  • Kotlin系列之let、with、run、apply、also

    简述: 相比Java, Kotlin提供了不少高级语法特性。对于一个Kotlin的初学者来说经常会写出一些不够优雅...

  • Kotlin-let、with、run、apply、also函数

    简述: 相比Java, Kotlin提供了不少高级语法特性。对于一个Kotlin的初学者来说经常会写出一些不够优雅...

  • 31 天,从浅到深轻松学习 Kotlin

    这篇文章介绍开发者用 31 天学习 Kotlin 的心得,深入浅出地介绍了 Kotlin 的一些基本特性以及高级用...

网友评论

    本文标题:kotlin高级特性

    本文链接:https://www.haomeiwen.com/subject/efmijktx.html