美文网首页Kotlin精讲-黑马程序员(原创)Kotlin编程Kotlin
kotlin精讲-第4章(4)kotlin 5大内置委托

kotlin精讲-第4章(4)kotlin 5大内置委托

作者: 739c8d412b4c | 来源:发表于2017-12-06 11:11 被阅读217次

    Kotlin标准库中,已经自定义了一系列标准委托,包括了大部分有用的委托。

    延迟加载(Lazy)

    定义

    lazy()是一个函数, 接受一个Lambda表达式作为参数, 返回一个Lazy类型的实例,这个实例可以作为一个委托, 实现延迟加载属性(lazy property): 第一次调用 get() 时, 将会执行 lazy() 函数受到的Lambda 表达式,然后会记住这次执行的结果, 以后所有对 get() 的调用都只会简单地返回以前记住的结果。

    语法结构

    案例分析

    针对延迟加载lazy,我们需要知道两个结论。

    1. 延迟属性只有在访问的时候才会被初始化。

    2. 延迟属性只会初始化一次。
      参考代码:

    针对以上代码,我们在7行打个断点,然后debug运行程序。可以看到【normalValue】已经赋值成功,而【lazyValue】则提示“Lazy value not initialized yet.”。
    参考截图:

    之所以出现现在的情况,因为我们还没有访问到【lazyValue】,我们接着执行完第17行,将会看到lazyValue被初始化了。
    参考截图:


    我们接着执行完所有代码,看结果输出:

    可以看到【println("lazyValue进行初始化")】只被输出了一次。所以,延迟属性lazy只初始化一次。

    可观察属性(Observable)

    定义

    Delegates.observable()函数接受两个参数: 第一个是初始化值, 第二个是属性值变化事件的响应器(handler)。这种形式的委托,采用了观察者模式,其会检测可观察属性的变化,当被观察属性的setter()方法被调用的时候,响应器(handler)都会被调用(在属性赋值处理完成之后)并自动执行执行的lambda表达式,同时响应器会收到三个参数:被赋值的属性, 赋值前的旧属性值, 以及赋值后的新属性值。

    语法结构

    其中Lambda表达式(变化事件的响应器)会在变量的setter()被调用的时候触发。

    Lambda里面可以获取三个参数:

    prop-被赋值的属性;

    old-赋值前的旧属性值;

    new-赋值后的新属性值;

    案例分析

    参考代码:

    针对以上代码,第13行和第16行代码对属性进行了修改,所以我们的属性变化事件响应器被触发了2次。

    Vetoable

    定义

    Delegates.vetoable()函数接受两个参数: 第一个是初始化值, 第二个是属性值变化事件的响应器(handler),是可观察属性(Observable)的一个特例,不同的是在响应器指定的自动执行执行的lambda表达式中在保存新值之前做一些条件判断,来决定是否将新值保存。

    语法结构

    Lambda 返回true:变量会被修改

    Lambda返回false:变量不会被修改

    案例分析

    参考代码:


    结果分析:

    针对以上代码,代码在第15行和第19行,对userName进行了修改,每次修改都触发了Lambda表达式的执行。但是第15行新的属性值【"heima"】不满足【new.contains("黑马")】,所以没有赋值,所以16行输出结果是【userName当前属性值:黑马程序员】。

    notNull

    定义

    对于一个不可为“non-null”的变量,我们需要保证它被正确的赋值。赋值操作可以在变量定义的时候,也可以后续代码里面进行赋值。我们只需要在变量后面使用notNull属性委托,编译器就允许我们后续进行赋值。

    加了notNull的属性委托,编译器允许我们后续赋值,那我们也有可能忘记赋值,这样使用变量的时候就会报空指针。那有的同学可能会说,我已经养成了良好的习惯,在使用变量之前会进行非空判断,这样的做法会导致有大量的非空判断,这是不美观的。其实这个时候即使做非空判断也会抛出异常(UninitializedPropertyAccessException)。因为notNull的属性委托,要求变量被引用的时候被赋值。

    语法结构

    案例分析

    参考代码:

    结果分析:

    针对以上代码的第11行,因为我们使用了notNull的属性委托,所以编译器允许【userName】后续进行赋值。

    针对以上代码的第16行对【user.userName】进行非空判断,然后在第17行进行使用,感觉上不会有什么问题,但是结果大家看到了,报了空指针异常。说明,我们用了notNull属性委托之后,在第16行的时候用到了【user.userName】,这个时候如果我们没有赋值就会抛出异常,提示“lateinit propety userName has not been initialized”。

    将多个属性保存在一个map

    定义

    Kotlin的map委托,提供了map和对象一一绑定关系,就是map的值可以决定对象的值,修改map的值也可以影响对象的值。但是这一切需要满足,map的key和属性的名称保证一致。

    语法结构

    val/var 变量: 变量类型by 实现Map接口的对象

    案例分析

    参考代码:

    提示:

    针对以上代码的第7行用到的【MutableMap】,也可以改为其他map,但是如果要想修改map集合里面的值,必须使用MutableMap接口对象。

    相关文章

      网友评论

        本文标题:kotlin精讲-第4章(4)kotlin 5大内置委托

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