kotlin编译失败_Kotlin 实战经验中的那些坑+最佳实践
“确认过“踩过坑”,遇上对的 kotlin”Num 1:方法入参是常量,不可修改 Java 与 Kotlin 互操中,Java 程序员会有点不适应class Main {/*** Kotlin 入参是常量*/fun print(a: Int = 1, b: String = "") {// a = 10; // 错误:Val canno...
“确认过“踩过坑”,遇上对的 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 体系控件搭配使用时,需要额外投入精力关注下。详情,可以进入传送门:不要总是相信 @JvmOverloads
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.javapublic 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() } }}
作者:海路IFEI
链接:https://juejin.cn/post/6910918847067324430
关注我获取更多知识或者投稿


更多推荐



所有评论(0)