可空性

在java中,运行一个程序,往往遇到的最多的错误就是空指针异常,而空指针异常他是个运行时异常,往往不会指明究竟是哪一行的问题,这就让程序员非常的头疼。

而kotlin的解决方案就是把运行时错误转为编译期的错误。让程序员可以在编译时就减少错误异常的产生。通过区分可空和非空两种数据类型。

可空类型

在kotlin中,所有的常见类型都是默认非空的,也就是不能接受null作为参数。除非显示的把他标记为可空,即在类型后面加上?

但是,一旦声明了是可控类型,就会有很多操作受到限制,kotlin会直接拒接一部分函数的调用,除非你对他进行了非空判断处理,然后kotlin系统就会只能判断类别,然后你才能继续执行。例如:

1
fun strLen(s:String?) = if(s!=null) s.length else 0

如果你不进行非空判断,他将不允许进行编译。

类型定义

类型就是数据的分类……决定了该类型可能的值,以及该类型的值上可以完成的操作。

在java中,他没有区分可空和非空,例如String类型可以接受String类型和null。而这在运行中就有可能导致空指针异常(NullPointerException)。而如果每次调用前都进行一次非空判断,就会大大降低代码的可读性。致使代码臃肿。

java中也提供了@Nullable和@NotNull的注解用来判断能否处理空值。或者直接使用Optional的一种包装类,用来确保没有null,但是这会导致代码变得冗余,额外的包装类还会影响运行时的性能。

Kotlin的可空类型提供了全面的解决方案。区分可空和非空类型使判断变得简单。

安全调用运算符:?.

kotlin工具库中最有效的一种工具就是安全调用运算符:?.
他允许你把一次null检查和一次方法调用合并成一个操作。

不只是可以调用方法,调用属性也是一样的,可以把检查过程和方法调用一起执行。

Elvs运算符:” ?: “

他可以方便的提供代替null的默认值,被称为Elvs运算符。

他常常和安全调用运算符一起使用,用一个值代替对null对象调用方法时返回的null。

1
fun strLen(s:String?) = s?.length ?: 0

Elvs的特殊用处,return和throw都是表达式,也就是说Elvs运算符也可以接return和throw。那么如果左边判断出为空,可以直接返回或者抛出异常。这个使用情况总是特别有用。

安全转化:” as? “


这个也很好理解,as就和类型转化符,如果检测到类型不匹配,将会返回一个空值。他也经常和Evls运算符一起使用。比如,重写Equals方法时:

1
2
3
4
5
class Person{
override fun equals(o:Any?):Boolean{
val other = o as? Person ?: return false
}
}

非空断言:” !! “

就是强制确保该类型一定不是null,尽管他是可空类型。如果他是null的话,将会抛出一个异常表明这个断言出现了问题,但是kotlin与java不一样的就是他会表明具体那个位置出现了问题,而不是单纯的报一个空指针异常。
通常不建议使用非空断言,因为他会凌驾于编译器之上,无法替你解决空值问题。

let函数

let函数本身没什么特点,他的作用是把一个调用他的对象变成lambda表达式的参数。但是如果结合安全调用运算符一起使用的话,

他就可以很好的解决在预判非空后实现内容。
而且如果一个表达式会返回一个对象,一般需要将该对象用一个变量存储,然后再使用该变量进行非空判断再执行操作。而let可以直接把这个表达式的对象进行非空判断后传入到lambda函数中作为参数使用。减少了内存的消耗。

延迟初始化的属性

他的作用场景就是,一个变量最终一定是非空的,但是在初始化化时,不知道给他传入什么非空值。而如果传入null,将会导致后期大量的非空判断处理。影响效率。
因此可以延迟初始化。他常常与一些框架中的依赖注入相互配合使用。为了保证框架的兼容性,kotlin会默认生成一个lateinit的属性的具有相同可见性的字段。

可空类型的扩展


对于可空类型数据的扩展函数。
可以不通过安全检测就直接调用,例如:

1
2
fun String?. isNullOrBlank () : Boolean = 
this == null 11 this.isBlank ()
  1. 泛型类和泛型函数都是默认可空的,他们都允许null的存在,即使T没有用?结尾,如果要限制非空,需要让泛型继承自Any,即非空泛型。

可空性和java


在java中可以通过注解实现和kotlin类似的效果。并且可以和kotlin的非空与空相互编译成功。

因为

平台类型本质上就是kotlin无法判断的可空性的类型。
他即可当作可空又可当作非可空
通过kotlin调用java时,一样需要满足相关的安全性判断,否则可能会抛出参数异常的报错

kotlin可以根据平台类型去多种方式的执行,继承相关的java代码。