Kotlin一步一步学(三) -- 延迟初始化和密封类

上一篇:Kotlin一步一步学(二) -- 标准函数和静态方法

延迟初始化

如果你的类中存在很多全局变量时,为了保证它们能通过Kotlin的空指针检查语法,你不得不做许多的非空判断才行,即使你非常确定它们不会为空。那么这个问题有没办法解决?答案是肯定的,那就是对全局变量进行延迟初始化。

延迟初始化就是在变量声明前使用lateinit 关键字,它可以告诉Kotlin编译器,我会在晚些时候对这个变量进行初始化,然后就不用在一开始的时候将它赋值为null,并且不用在调用的地方做非空的判断。

原始的写法

class MainActivity : AppCompatActivity(), View.OnClickListener {

    private var adapter: MyAdapter? = null  //没有进行初始化,类型后面必须加一个?,并且赋值为null

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        adapter = Mydapter(mylist)
    }

    override fun onClick(v: View?) {
        ...
        adapter?.notifyItemInserted(mylist.size - 1)  //调用adapter的时候要进行判空

    }
}

lateinit延迟初始化写法

class MainActivity : AppCompatActivity(), View.OnClickListener {

    private lateinit var adapter: MyAdapter   //使用lateinit进行延迟初始化声明,不需要赋值为null

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        adapter = Mydapter(mylist)
    }

    override fun onClick(v: View?) {
        ...
        adapter.notifyItemInserted(mylist.size - 1)  //调用adapter的时候不需要进行判空

    }
}

\color{red}{PS:}当你对一个全局变量使用了lateinit关键字时,请一定要确保它在被任何调用前已经完成了初始化,否则程序就会抛出UninitializedPropertyAccessException异常。
我们可以API来判断一个全局变量是否已经完成了初始化,这样可以避免报错和重复对某个变量进行初始化。对上面示例进行优化

class MainActivity : AppCompatActivity(), View.OnClickListener {

    private lateinit var adapter: MyAdapter   //使用lateinit进行延迟初始化声明,不需要赋值为null

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        if (!::adapter.isInitialized)   //判断adapter是否已经初始化
             adapter = Mydapter(mylist)
    }
}

密封类

密封类用来表示受限的类继承结构:当一个值为有限几种的类型、而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。

要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明。

sealed class Result
class Success(val msg: String) : Result()
class Failure(val error : Exception) : Result()

使用密封类的关键好处在于使用when 表达式的时候,如果验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。

fun getResult(result: Result) : String = when(expr) {
    is Success -> result.msg
    is Failure -> "Error is ${result.error.message}"
    // 不再需要 else 子句,因为我们已经覆盖了所有的情况
}

\color{red}{PS:}sealed经常用于在adapter中和viewHolder一起使用,达到简化adapter代码的效果。

下一篇:一步一步学(四)

推荐阅读更多精彩内容