Kotlin浅析延迟初始化与密封类的实现方法

作者:m0_63970488 时间:2023-05-06 13:54:44 

一、lateinit延迟初始化关键字

Kotlin中很多语法特性,如变量不可变,变量不可为空,等等 这些特性都是为了尽可能地保证程序安全而设计的,比如你的类中存在很多全局变量实例,为了保证它们的能够满足Kotlin的空指针检查语句标准,你不得不做非空判断保护,即使你非常确定它们不会为空。

下面距离看一下 :

class MainActivity : AppCompatActivity() {
   private var s: String? = null
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)
       s = "test"
       Log.d("TAG", "onCreate: ${s!!.length}")
   }
}

我们将s 设置为了全局变量 , 但是它的赋值工作在onCreate()方法进行的,因此不得不将s赋值为null。

虽然你确定在打印前已经将s赋值成功,但是打印s的长度仍然要进行判空处理才行,否则编译不通过。

当你的代码中越来越多的全局变量实例时,这个问题就会变得越来越明显,到时候可能必须写大量额外判空处理的代码,却只是为了满足Kotlin的编译要求。

幸运的是,这个问题有解决办法的且非常之简单,就是对全局变量进行延迟初始化。

初始化使用的关键字 lateinit ,它可以高速编译器,我会在晚些时候对这个变量进行初始化,这样就不用一开始就赋值为null了。

class MainActivity : AppCompatActivity() {
   private lateinit var s: String
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)
       s = "test"
       Log.d("TAG", "onCreate: ${s.length}")
   }
}

可以看到,加上了lateinit关键字 ,这样一开始就不用赋值为null了,打印长度的时候也不用进行判空处理了,当然使用lateinit关键字 也不是没有风险,如果没有进行赋值,那么程序一定会崩溃,并抛出异常。

另外,我们可以通过代码来判断全局变量是否已完成了初始化工作,这样某些时候可以有效避免重复对某一个变量进行初始化操作。

class MainActivity : AppCompatActivity() {
   private lateinit var s: String
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)
       if (!::s.isInitialized) {
           s = "test"
       }
       Log.d("TAG", "onCreate: ${s.length}")
   }
}

二、使用密封类优化代码

新建一个Kotlin文件,代码如下 :

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

这里定义了一个Result接口,用于表示某个操作的执行结果,接口中没有编写任何内容。然后定义了两个类去实现Result接口:一个Success类用于表示成功时结果,一个Failure类用于表示失败时结果。

接下来再定义一个getResultMsg()方法 ,用于获取最后执行结果的信息,代码如下:

fun getResultMsg(result: Result) = when (result) {
   is Success -> result.msg
   is Failure -> result.error.message
   else -> throw IllegalArgumentException()
}

getResultMsg()方法中接受一个Result参数,我们通过when语句来判断,如果Result属于Success就返回成功的消息,如果Result是Failure就返回错误的信息,到目前为止代码是没什么问题的,烦人的是不得不写一个else条件语句,否则Kotlin编译不通过,其实代码永远也走不到else里 因为只有两种类型的存在,只是为了满足Kotlin的语法而已。

另外,编写else条件还有一个潜在的风险,如果我们新增一个Unknown类并实现了Result接口,用于表示未知的执行结果,但是忘记了在getResultMsg()方法中添加相应的条件,编译器不会提醒我们的,而是直接进入else条件里面去,从里面抛出异常并导致程序崩溃。

Kotlin的密封类很好的解决了此问题,密封类的关键字是sealed class ,它的用法同样很简单,我们可以轻松的将Result接口改造成密封类写法:

sealed class Result
class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()
fun getResultMsg(result: Result) = when (result) {
   is Success -> result.msg
   is Failure -> result.error.message
}

代码没什么变化,只是将interface改成了 sealed class。密封类是一个可继承的类,因此在继承它的时候还需要加上一对括号。

密封类的优点是,可以再getResultMsg() 方法中取消else条件语句。

为什么取消掉else条件语句还能编译通过呢,Kotlin编译器会自动检查该密封类有哪些子类,并强制要求将每一个子类所对应的条件全部处理。这样就可以保证,即使没有else条件,也不可能出现漏写的情况,如果现在新增一个Unknown类,并也让它继承自Result,此时getResultMsg()方法就一定会报错,必须添加Unknown语句条件才能编译通过。

注意:密封类及其所有子类只能定义同一个文件的顶层位置,不能嵌套在其他类中,这也是被密封类底层实现机制所限制的。

来源:https://blog.csdn.net/m0_63970488/article/details/126065532

标签:Kotlin,延迟初始化,密封类
0
投稿

猜你喜欢

  • C#泛型的使用案例

    2023-10-01 23:24:00
  • C#使用FileStream复制一个任意文件

    2022-04-17 19:55:17
  • Android游戏开发实践之人物移动地图的平滑滚动处理

    2023-12-26 19:45:41
  • android实现简单的活动转盘

    2022-11-29 08:40:35
  • Spring Boot应用监控的实战教程

    2022-03-02 18:17:09
  • c# 服务器上传木马监控代码(包含可疑文件)

    2022-07-08 10:02:45
  • java 生成xml并转为字符串的方法

    2023-01-07 08:27:30
  • AndroidStudio替换项目图标ic_launcher操作

    2023-03-20 09:48:07
  • Java利用openoffice将doc、docx转为pdf实例代码

    2023-08-07 23:44:34
  • java实现猜拳游戏

    2023-08-04 04:23:52
  • Android LayoutInflater.inflate源码分析

    2022-06-06 17:02:05
  • C#实现的字符串转MD5码函数实例

    2023-03-02 15:34:43
  • Android解析XML文件升级APK的方法

    2022-06-05 20:47:26
  • 深入解析Java的Spring框架中bean的依赖注入

    2023-12-20 18:50:52
  • Spring源码解析之编程式事务

    2023-06-20 19:17:49
  • c#同步两个子目录文件示例分享 两个文件夹同步

    2022-01-25 05:03:03
  • 继承JpaRepository后,找不到findOne()方法的解决

    2022-08-26 18:33:26
  • Android开发之设置开机自动启动的几种方法

    2021-12-04 20:35:37
  • Spring Security中用JWT退出登录时遇到的坑

    2022-05-19 10:30:28
  • 实例代码讲解JAVA 观察者模式

    2023-09-11 19:22:18
  • asp之家 软件编程 m.aspxhome.com