第一种直接引用Java类,中招指数 三颗星!!!
再android studio中,使用kotlin 调用一个会返回空的java函数, 是不会提示空安全的,只有加上@nullable之后才会提示。
public static T jsonToObj(String json, Class tClass) {
if (TextUtils.isEmpty(json) || tClass == null) {
return null;
}
…
…
…
return item;
}
其实文档中说的很清楚。
举例:
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
虽然我们定义的属性是非空的,但由于上述原因,kotlin无法判空java传过来的值,所以这个json实体类的属性还是有可能为空的。但由于IDE只是识别出了我们定义的是非空属性, 而没有考虑对java的调用可能导致为空,所以他会明确的提示你, 属性不可能为空。。还会给出一个警告⚠️~
这时候在哪里调用这个属性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)
我们数据传入的是jsonString很明显str字段是个空的,gson解析出来也是空的, 所以会打印这句话,而且单元测试的断言是可以tests passed的。但是,倔强的IDE还在提示不需要判空...
有的同学可能习惯性的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;
}
测试用例通过, 就酱。