1. 数据类
我们经常需要创建保存数据的类,在Kotlin中,这种类叫数据类并标记为data
:
data class User(val name: String, val age: Int)
为了确保生成代码的一致性和有意义的行为,数据类必须满足以下要求:
- 主构造函数需要⾄少有⼀个参数;
- 主构造函数的所有参数需要标记为 val 或 var ;
- 数据类不能是抽象(
abstract
)、开放(open
)、密封(sealed
)或者内部的(inner
);
2. 空安全
Kotlin的类型系统旨在从我们的代码中消除NullPointerException(NPE)
。在Kotlin中抛出NPE
的原因是:
- 显示调用
throw NullPointerException()
; - 使⽤了
!!
操作符; - 外部 Java 代码导致的;
- 对于初始化,有⼀些数据不⼀致(如⼀个未初始化的 this ⽤于构造函数的某个地⽅)。
在Kotlin中,类型系统会判断一个引用可以为空还是不能为空。例如,String类型的常规变量不能为空:
var a: String = "abc"
a = null // 编译错误
如果要允许为空,我们可以声明一个变量为可空字符串,写作String?
:
var b: String? = "abc"
b = null // ok
现在,如果你调a
的方法或者访问它的属性,它保证不会抛出NPE
,这样你就可以放心地使用:
val l = a.length
但是如果你想访问b
的同一个属性,那么这是不安全的,并且编译器会报告一个错误:
val l = b.length // 错误:变量“b”可能为空
但是我们还是要访问该属性该怎么办:
1. 在条件中检查null
你可以显式检查b
是否为null
:
val l = if (b != null) b.length else -1
2. 安全的调用
b?.length
如果b
非空就返回b.length
,否则返回null
,这个表达式的类型是Int?
。
如果要只对非空值执行某个操作,安全调用操作符可以与let
一起使用:
val listWithNulls: List<String?> = listOf("A", null)
for (item in listWithNulls) {
item?.let { println(it) } // 输出 A 并忽略 null
}
3. Elvis 操作符
val l = b?.length ?: -1
如果?:
左侧表达式为空,elvis操作符就返回其左侧表达式,否则返回右侧表达式。请注意,当且仅当左侧为空时(?.
前面为空或者后面为空都满足),才会对右侧表达式求值。
4. !! 操作符
val l = b!!.length
我们可以写b!!
,这会返回一个非空的b
值或者如果b
为空,就会抛出NPE
。
3. 区间
没有左开右闭区间!!!
4. sortedBy
/**
* Returns a list of all elements sorted according to natural sort order of the value returned by specified [selector] function.
*/
public inline fun <R : Comparable<R>> IntArray.sortedBy(crossinline selector: (Int) -> R?): List<Int> {
return sortedWith(compareBy(selector))
}
按照指定选择器返回一个根据自然排序的集合。
5. inline(内联)
// public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException
inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T = this.fromJson(json, T::class.java)