likes
comments
collection
share

记录一次Java Convert Kotlin造成的空指针异常

作者站长头像
站长
· 阅读数 12

不知道大家在使用Kotlin进行编码的时候,有没有直接使用AS的Code -> Convert Java File 2 Kotlin File这个功能,此功能在日常使用中还是比较实用的,可以帮助我们将老的Java或者复制的Java代码(😃)一键转换成Kotlin代码,最近在使用此功能的时候竟然遇到了空指针的Crash,在此记录一下,顺便也给大家做个预警。

起因

在工程中引入了三方的SDK,此SDK使用Java编码,我们需要实现它的一个回调方法做一下异常处理,SDK具体方法就不贴出来了,下面模拟一下他们的回调

public class Test {

    // 定义回调接口,其中error用来处理异常情况,参数为Exception对象
    public interface TestCallback {
        void test();

        void error(Exception e);
    }

    // 传入回调并直接模拟调用它的方法
    public void setTest(TestCallback testCallback) {
        testCallback.test();
        testCallback.error(new Exception("test"));
    }
}

模拟了它们的回调接口,然后在setTest(callback)中直接调用接口方法,这里先看一下这个error的接口方法,它的参数exception并没有使用可空(@Nullable)或者非空(@NonNull)注解来定义,默认就是可空类型。

然后我们直接模拟调用下看看具体效果,先用Java代码来调用

public class Java2Kt {

    private final Test testCallback = new Test();

    public void test() {
        testCallback.setTest(new Test.TestCallback() {
            @Override
            public void test() {
                Log.d("taonce", "Java2Kt test");
            }

            @Override
            public void error(Exception e) {
                if (e != null) {
                    Log.d("taonce", "Java2Kt error " + e.getMessage());
                }
            }
        });
    }
}

# 
Java2Kt test
Java2Kt error java.lang.Exception: custom exception

这样就没得毛病,可以正确调用并输出日志,然后我们改一下setTest(callback)方法,再额外添加一行

public void setTest(TestCallback testCallback) {
    testCallback.test();
    testCallback.error(new Exception("test"));
    // 新增
    testCallback.error(null);
}

即使我们在error()调用的地方传入null也不会出现什么问题,因为我们在回调实现的时候加入了非空判断,但是我们使用Convert Java File 2 Kotlin File转换成Kotlin之后再看看代码

class Java2Kt {
    private val testCallback = Test()
    fun test() {
        testCallback.setTest(object : TestCallback {
            override fun test() {
                Log.d("taonce", "Java2Kt test")
            }

            override fun error(e: Exception) {
                if (e != null) {
                    Log.d("taonce", "Java2Kt error " + e.message)
                }
            }
        })
    }
}

这样乍一看是不会出现问题的,因为转换成KT之后,非空判断也是有的,但是此时AS会在非空判断的地方报警告⚠️,提示我们Condition 'e != null' is always 'true',习惯性的就会将这个非空给去掉,去掉之后一运行直接来了一个空指针异常😂

分析

AS的Convert Java File 2 Kotlin File功能在转换过程中,如果参数未使用可空或者非空注解,转换之后默认是非空类型,这样就会导致我们在使用的时候不太注意此参数的可空类型,有时会丢掉可空检查,这样在程序运行的过程中就会出现空指针的可能,再来看看直接使用KT实现回调的代码

test.setTest(object : Test.TestCallback {
    override fun test() {
        Log.d("taonce", "MainActivity test")
    }
    // 默认为可空类型
    override fun error(e: Exception?) {
        Log.d("taonce", "MainActivity test ${e?.stackTraceToString()}")
    }
})

如果直接使用KT来编码,实现TestCallback的时候error(exception?)是默认加上了可空(?)的,很明确的告知开发者需要注意此参数可能为空,需要在使用的时候加上可空判断。所以直接使用KT是大概率的不会出现空指针的情况了。

小结

  1. AS的Convert Java File 2 Kotlin File功能固然是给开发者提供了便捷的操作,但是也需要开发者使用之后谨慎判断
  2. 对于自己使用Java写的一些回调,尽可能的加上可空或者非空的注解,可以给调用者提供一些警示信息
  3. 在日常编码中,编码细节一定要处理得当,空指针无可避免但也需要最大化的避免此种异常,KT在这方面已经为开发者提供了较为安全的操作了
转载自:https://juejin.cn/post/7238153003282022437
评论
请登录