JAVA空安全_Kotlin的空安全

在许多的编程语言(例如Java)中最常见的遇到的陷阱之一,就是访问引用的成员会导致空指针异常的情况(NullPointerException),在Kotlin中的做了空安全的设计,从而避免了NullPointerException。

Kotlin的空安全设计

简单来说就是通过IDE的提示来避免调用null的对象,从而避免了NullPointerException,在androidx里就有通过一个@NonNull的注解就可以标记变量是否为空,然后IDE会帮助检查。到了Kotlin这里就有了语言级别的支持,IDE的提示级别从警告变成了错误,拒绝编译。接下来看看Kotlin的实现空安全做了哪些措施。

变量默认都是不为空的

d2491bbf8150

image.png

可以看到在上面的定义的时候赋值为空的时候,编译器就会提示出现错误,所有的默认变量都是不允许为空的。那么有时间在请求服务器数据的时候,有一些变量是会出现为空的情况,那该怎么办呢?

可以在变量的类型上面加上一个?号,这样就可以解除非空的限制。

d2491bbf8150

image.png

那么这样不是还是会出现空指针异常的情况吗。

安全的调用(?.)

在上面提到通过?号可以解除非空的限制,既然赋值可能会出现为空,那么为了避免空指针的异常,kotlin的做法就是在调用方进行处理——安全的调用。通过?.的方式进行调用。

d2491bbf8150

image.png

上面的?.的意思就是,如果str非空,就返回b.length,否则返回null。如果最后返回为null的话,我们还可以进行一步的处理。

使用Elvis操作符?:

在上面提到的如何str为空,那么length返回为空,这样好像也不太好,这是我们可以使用Elvis操作符:

d2491bbf8150

image.png

意思就是当前面为空的时候就返回-1。Elvis还有另一种常见的用法:

d2491bbf8150

image.png上面的写法就等价与下面的:可以看到进一步简化了代码。

d2491bbf8150

image.png

!!操作符

!!是非空断言运算符,也是避免空指针异常的手段方式之一,若该值为空则抛出异常。

d2491bbf8150

image.png

意思就编译器不再帮助检查,有什么后果需要程序员去承担,这种方式,实际上和Java就没上两样了。

安全的类型转换

如果对象不是目标类型,那么常规类型转换可能会导致 ClassCastException。 另一个选择是使用安全的类型转换,如果尝试转换不成功则返回 null:

val aInt: Int? = a as? Int

可控类型的集合

如果你有一个可空类型元素的集合,并且想要过滤非空元素,你可以使用 filterNotNull 来实现:

val nullableList: List = listOf(1, 2, null, 4)

val intList: List = nullableList.filterNotNull()

Kotlin的空安全设计,带来了很多好处,但是有的时候我们不一定能在定义的时候赋值,例如在Android开发的时候初始化一个控件的时候,findViewById()是需要在onCreate之后就调用的,那么这种情况怎么处理比较合适呢?

一:利用lateinit关键字进行延迟初始化

延迟初始化的意思是,告诉编译我无法第一时间去初始化,但是在使用前肯定会完成初始化。

private lateinit var textView:TextView

override fun onCreate(savedInstanceState: Bundle?) {

textView=findViewById(R.id.textView)

}

但是延迟初始化并不好,这样跟Java的属性没什么区别了,体验不到了空安全设计到带来的好处,而且 lateinit只能修饰var的属性,那么val的呢?

二:利用by Lazy惰性初始化

lazy()是接受一个 lambda 并返回一个 Lazy 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。也就是说只有第一次调用该属性的时候,委托方法才会被执行。并且只能修饰val的属性。

为了进一步安全使用,上面的TextView的初始化,就可以使用by lazy()了

private val textView by bindView(R.id.textView)

private val Activity.viewFind:Activity.(Int)->View?

get()={

findViewById(it)

}

fun Activity.bindView(id:Int):Lazy = lazy{

viewFind(id) as V

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值