“确认过“踩过坑”,遇上对的 kotlin
”
Num 1:方法入参是常量,不可修改
Java 与 Kotlin 互操中,Java 程序员会有点不适应
class Main {
/**
* Kotlin 入参是常量
*/
fun print(a: Int = 1, b: String = "") {
// a = 10; // 错误:Val cannot be reassigned!!!
}
}
复制代码
Num 2:不要 Companion
、INSTANCE
?
Java 访问 Kotlin 中定义的静态变量以及静态方法,需要 Companion
。例如:
// Main.kt
class Main {
companion object {
val EMPTY = ""
fun isEmpty(string: String = EMPTY) {
//todo code
}
@JvmField
val FULL_NUMBER = "1234567890"
@JvmStatic
fun isNumber(string: String = FULL_NUMBER) {
//todo code
}
}
}
复制代码
// Test.java
class Test {
public static void main(String[] args) {
// Java 访问 Kotlin 中的常量
Keng.Companion.getEMPTY();
Keng.Companion.isEmpty("");
KengInstance.INSTANCE.getEMPTY();
// Java 访问 Kotlin 中带有 JvmField 修饰的常量,无需 Companion
String FULL_NUMBER = Keng.FULL_NUMBER;
// Java 访问 Kotlin 中带有 JvmStatic 修饰的方法,无需 Companion
Keng.isNumber("");
}
}
复制代码
不想使用 Companion
, @JvmField
、 @JvmStatic
注解了解一下。
在 Kotlin object Main{...}
定义的静态对象依旧适用。
这些注解,特别推荐在Kotlin中使用,它们让Java与Kotlin互操,如丝般顺滑,没有任何一点点改变,就当什么都没发生过一样。
Num 3:Java 重载,在 Kotlin 中怎么巧妙过渡一下?
Kotlin 调用 Kotlin 中的方法,如果有默认参数,是可以不传递参数的。Java 与 Kotlin 互操中,好像还是需要传?
例如: isNumber(string: String = FULL_NUMBER)
:
// Test.java
class Test {
public static void main(String[] args) {
Keng.isNumber("");// 必须要传递个参数
}
}
复制代码
能不能让 Java 也享受到 Kotlin 默认参数的快乐?
// Test.java
class Test {
public static void main(String[] args) {
// JvmOverloads 注解的作用,默认实现了 重载 特性
Keng.isNumberWithOverLoads();
Keng.isNumberWithOverLoads("");
}
}
复制代码
注意:@JvmOverloads与Android View 体系控件搭配使用时,需要额外投入精力关注下。
Num 4:Kotlin 中的判空姿势
如下代码,在 Java
中应该还好,但在 Kotlin
中是无法通过编译器编译的。
var nullableString: String? = null
...
fun testNullableString() {
if (nullableString != null) {
var nullableStringLength = nullableString.length // 此处会报错!!!
}
}
复制代码
会报如下错误:
Error:(9, 40) Kotlin: Smart cast to 'String' is impossible, because 'nullableString' is a mutable property that could have been changed by this time
所以,在kotlin中,正确的判空姿势应该是如下的样子:
fun testNullableString() {
var nullableStringLength = nullableString?.length
}
复制代码
Num 5:Kotlin 复写 Java 父类中的方法,这里有坑:
第一步:Java 父类定义 onDialogCreate
,其中包含一个非空参数:savedInstanceState
// JavaKengBase.java
public class JavaKengBase {
public void onDialogCreate(Object savedInstanceState) {
// todo nothings
}
}
复制代码
第二步:Kotlin 继承并复写 JavaKengBase
class Keng : JavaKengBase() {
override fun onDialogCreate(savedInstanceState: Any) {// 注意:此处,是Any,不是Any?
super.onDialogCreate(savedInstanceState)
}
}
复制代码
第三步:利用 Java 多态特性,调用 onDialogCreate,并传入 null
参数
public class KengJava {
public static void main(String[] args) {
JavaKengBase keng = new Keng();
keng.onDialogCreate(null);// 注意:空参数
}
}
复制代码
这里可以有两个问题:
第一个:"overrides nothing"
原因就在 onDialogCreate(savedInstanceState: Any)
方法定义中的:Any
,不是Any?
上。
注意: 不要相信 AS 编译器,使用快捷键 Override Method 时,还是需要额外关注参数是否 Nullable?
Error:(17, 5) Kotlin: 'onDialogCreate' overrides nothing
第二个:IllegalArgumentException: Parameter specified as non-null is null
就算通过了编译,但在运行时,可能会抛出 Parameter specified as non-null is null
异常,这个异常也是Java
与Kotlin
混合开发中的高频异常。
综上:上述问题,很好解决,只需要在方法参数后面,增加一个?
即可。
override fun onDialogCreate(savedInstanceState: Any?)
复制代码
Num 6:Kotlin “狠”起来,连TODO
都不放过!
就下面这个平淡朴实无奇的 TODO()
,却会抛出一个 RuntimeException
!
fun testTodo(): Unit {
TODO()
}
复制代码
这个错误就是:kotlin.NotImplementedError: An operation is not implemented.
,让我们看看 TODO()
的实现:
public inline fun TODO(): Nothing = throw NotImplementedError()
复制代码
Num 7:is
、as
中的坑
obj is String
之后,作用域之中,类型就已经转换了,有点类似 java 的多态。
fun testAsIs() {
var obj: Any? = null
if (obj is String) {// 方法体内的作用域,obj 就是 String
var length = obj.length
}
}
复制代码
as
的两种不推荐写法,会抛出异常:TypeCastException: null cannot be cast to non-null type kotlin.String
//错误写法1,text不是String或为空时,会报异常
var strAble1 = text as String
//错误写法2,text不是String时,同样会报异常
var strAble2 = text as String?
复制代码
as
的推荐写法:
//正确写法,转换失败自动转换为空对象
var strAble = text as? String
复制代码
Num 8:Kotlin 中的 Property 的理解
在Kotlin中一个 property 不管有没有 backing field 都称之为 property,而在 Java 中 field + get、set方法一起才能是一个 property。
var age = 0
set(value){
age = value + 1
}
复制代码
这样写其实是会发生递归,无法赋值成功。
珠玉在前,就不重复造轮子了。额外感兴趣的,可以进入传送门 : Howshea 理解 Kotlin 中的属性(property)
因为 实践中的坑总是伴随着最佳实践一起出现,所以,最后附上几则最佳实践,以飨读者:
Num 1:also
关键字,最佳实践:
while (bufferReader.readLine().also({ line = it }) != null) {
// do something
}
复制代码
相当于 Java 中的:
while ((line = bufferReader.readLine()) != null) {
// do something
}
复制代码
Num 2:takeIf
关键字,最佳实践:
// 原代码
if (someObject != null && status) {
doThis()
}
// 最佳实践
someObject?.takeIf{ status }?.apply{ doThis() }
复制代码
Num 3:单例模式的写法
关于设计模式的写法,珠玉在前,同样不重复制造轮子了,传送门:Kotlin的5种单例写法和java对比。
//Java实现
public class Singleton {
private volatile static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
//kotlin实现
class Singleton private constructor() {
companion object {
val instance: Singleton by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
Singleton()
}
}
}
网友评论