继续跟着官方文档学习,再也不说kotlin坑了,感觉坑的是我而不是kotlin。
1、操作符的重载介绍了一些操作符的执行过程以及对应的函数,要是我把文档抄一遍似乎没啥意义。我的理解是操作符会被当作对应的函数来调用。特殊地,赋值在kotlin中不是表达式。“null == null”总返回true,如果x已经定义了不可为空,那么“x == null”总为为false而不调用equals(废话.....),此外,命名函数的中缀调用在前面(第11篇文章)已经介绍过了。
2、java中,任何引用都可以是null,而调用null对象会产生NullPointerException(简称NPE),而kotlin的语言设计想要消除该异常。首先得知道这个异常产生的几种情况,
(1)显式调用 throw NullPointerException()
(2)使用了下文描述的 !! 操作符
(3)外部 Java 代码导致的
(4)对于初始化,有一些数据不一致(如一个未初始化的 this用于构造函数的某个地方)。
在kotlin中,类型系统会自动识别一个引用能否为空。例如:字符串类型如果不加问号声明为可空,则无法将其赋值为null。类似地,如果已经声明了一个字符串为可空,那么不能调用length属性,因为它是不安全的。
3、那么问题来了,对于一个可空对象,我们如何引用呢?办法一、使用if...else进行非空判断,当然要注意该对象是不可变的,否则判断后又变为null了就白费了。
4、既然有办法一自然有办法二,叫做安全调用,就是在调用时加个“?”表示是否为空?为null则返回“”null””如果想要忽略null,可以与let合用。
fun main(args: Array<String>) {
var s: String? = null
println(s?.length)
s?.let { println(it) }
}
5、Elvis操作符使用“?:”表示,如果左侧非空则执行左侧表达式,否则返回右侧表达式的值。
fun main(args: Array<String>) {
var s: String? = null
println(s?.length ?: -1)
}
6、“!!”操作符用于显示获取NPE异常,如果不加的话连编译都不通过。
fun main(args: Array<String>) {
var s: String? = null
println(s.length)
// println(s!!.length)
}
7、基本类型的转换使用其to*方法,而其它类型的转换使用as时有可能造成ClassCastException,所以使用安全的类型转换,即在as前加一个问号。
open class A() {}
fun main(args: Array<String>) {
val a: A = A()
val b: Long = 1
val aInt: Int? = a as? Int
val bInt: Int? = b.toInt()
println(aInt)
println(bInt)
val cInt: Int? = a as Int
println(cInt)
}
8、对于可空集合可以用filterNotNull方法来过滤掉非空元素
fun main(args: Array<String>) {
val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()
intList.forEach { print(it) }//输出124
}
9、类似于java,kotlin中所有异常类都是Throwable的子孙类,使用throw抛出异常,使用try...catch...finally...捕获异常。try是一个表达式,返回值由try块或者catch块最后的表达式决定,与finally无关。
fun main(args: Array<String>) {
val a: Int? = try {
parseInt("12")
} catch (e: NumberFormatException) {
null
}
println(a)
val b: Int? = try {
parseInt("12.5")
} catch (e: NumberFormatException) {
null
}
println(b)
}
10、kotlin没有受检的异常。。。不懂。
11、throw也是表达式,所以可以作为Elvis表达式的一部分。
data class Person(val name: String?)
fun main(args: Array<String>) {
val person = Person(null)
val s = person.name ?: throw IllegalArgumentException("Name required")
println(s)
}
12、throw表达式的类型是特殊类型Nothing。该类型没有值,而是用于标记永远不可能达到的代码位置。如下:fail没有返回值。
data class Person(val name: String?)
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
fun main(args: Array<String>) {
val person = Person(null)
val s = person.name ?: fail("Name required")
println(s) // 在此已知“s”已初始化
}
13、注解是将元数据附加到代码的方法(不懂),使用annotation声明。。。
注解的附加属性可以通过用元注解标注注解类来指定(一脸懵逼,不懂,怎么看起来有点像标签)。管他的,先记住再说。
对主构造函数注解时必须有constructor关键字。
注解也可以标注属性访问器。
注解可以带参数,但参数不能可空。
注解可以作为参数,但此时不带“@”。
类作为注解参数时,需要使用kotlin类。
注解可用于lambda表达式体的invoke方法上。
属性或者主构造函数参数可以精确标记注解。
对于同一目标有多个注解的情况。可以在目标后添加方括号并把注解放在里面。
支持的使用处目标的完整列表如下:
file(标注整个文件,需要放在文件顶层、package之前)
property (具有此目标的注解对 Java 不可见)
field(标注java字段)
get (属性 getter)
set (属性 setter)
receiver (扩展函数或属性的接收者参数)
param (构造函数参数)
setparam (属性 setter 参数)
delegate (为委托属性存储其委托实例的字段)
14、java注解与kotlin注解100%兼容。
调用java注解时,需要使用命名参数语法。
特殊地。value参数的值无需显示指定。如果value具有数组类型,kotlin中会成为vararg可变数量参数。
//java
public @interface AnnWithValue {
String[] value();
}// Kotlin
@AnnWithValue("abc","def") class C
对于其它数组型参数,需要显示使用arrayOf。
//java
public @interface AnnWithValue {
String[] v();
}// Kotlin
@AnnWithValue(v= arrayOf("abc","def")) class C
15、注解实例的值会作为属性暴露给kotlin代码。
// Java
public @interface AnnWithValue {
int value();
}
// Kotlin
fun foo(annWithValue: AnnWithValue ) {
val i = annWithValue.value
}
今天就到这里吧。。。继续去copy和paste去了