kotlin和java混用空安全的问题

第一种直接引用Java类,中招指数 三颗星!!!

再android studio中,使用kotlin 调用一个会返回空的java函数, 是不会提示空安全的,只有加上@nullable之后才会提示。

public static  T jsonToObj(String json, Class tClass) {
    if (TextUtils.isEmpty(json) || tClass == null) {
        return null;
    }
    …
    …
    …

    return item;
}

其实文档中说的很清楚。


WechatIMG595.png

举例:

val entity = GsonUtil.jsonToObj("", Entity::class.java)
entity.let {}//这里没有空安全提示,但是确实会返回空

这种情况就只能我们自己小心了,调用java时候要记得判空。

也可以加上@nullable注解, 这个IDE是可以识别的。

@nullable
public static  T jsonToObj(String json, Class tClass) {}

这样就会提示空安全了。
所以kotlin调用没有被标记nullable的函数一定要当心!

第二种 使用一些库,比如Gson,隐蔽指数 五颗星!!!

先举个例子。

很多时候我们定义的实体类的每个字段都是有用的, 想从源头上避免空指针, 而不是在后续取数据的时候写一堆的?操作符,所以很自然的就会想到
定义为非空类型的属性,比如
data class En(val str:String)

但是第一种情况的问题还是存在的,比如使用Gson来解析
val json = Gson().fromJson(jsonString,En::class.java)
虽然我们定义的属性是非空的,但由于上述原因,kotlin无法判空java传过来的值,所以这个json实体类的属性还是有可能为空的。但由于IDE只是识别出了我们定义的是非空属性, 而没有考虑对java的调用可能导致为空,所以他会明确的提示你, 属性不可能为空。。还会给出一个警告⚠️~

WechatIMG596.png

这时候在哪里调用这个属性str,编译期都会提示非空,怂恿你去掉判空。。

然鹅,我们做一个小小的单元测试就知道了

@Test
fun addition_isCorrect() {
 
    val jsonString = "{str:null}"
    val json = Gson().fromJson(jsonString,En::class.java)
    if (json.str == null) {
        println("test assert json.str = null")
    }
    assertEquals(json.str,null)
}
data class En(val str:String)
2019040317264375.png

我们数据传入的是jsonString很明显str字段是个空的,gson解析出来也是空的, 所以会打印这句话,而且单元测试的断言是可以tests passed的。但是,倔强的IDE还在提示不需要判空...

WechatIMG597.png

有的同学可能习惯性的alt+enter,就把判空去掉了,导致NPE。

可见混用还是不能依赖IDE的提示,需要自己来判断!

虽然说可以在实体类就设置属性为可空类型, 类似val s:String?,但是未免让kotlin的特意设计(官方介绍大篇幅吹比)的空安全特性显得略显无用武之地,所以这里给出一种解决方案提供给使用Gson而且服务器返回为null并没有特殊含义的同学们使用,就是Gson解析时候使用反射把类型为String且为null的属性赋值为空字符串“”。

/**
      /**
     * object to json 的工具类
     * 所有为null的String类型都会被赋值为""
     * @param 
     * @return
     */
    public static  T jsonToObj2(String json, Class tClass) {
        if (TextUtils.isEmpty(json) || tClass == null) {
            return null;
        }
        T item = null;
        try {
            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
                        .enableComplexMapKeySerialization().create();
            item = gson.fromJson(json, tClass);

            Class itemClass = item.getClass();
            Field[] fields = itemClass.getDeclaredFields();
            for (Field f : fields) {
                f.setAccessible(true);
                Type type = f.getGenericType();
                Object obj = f.get(item);
                if (obj == null && type.toString().contains("String")) {
                    f.set(item, "");
                }
            }
        } catch (JsonSyntaxException e2) {
            Log.d(TAG, "jsonToList: JsonSyntaxException error");
        } catch (JsonParseException e1) {
            Log.d(TAG, "jsonToList: JsonParseException error");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return item;
    }

20190429175101483.png

测试用例通过, 就酱。

你可能感兴趣的:(kotlin和java混用空安全的问题)