Kotlin自定义getter访问时触发NullPointerException的原因是什么?
问题根因
- 核心原因1:
nameInitials是类内部声明的属性,没有放在主构造参数中,如果你使用@Parcelize实现Parcelable序列化、或者用Gson/Jackson等JSON解析库反序列化实例时,该属性的初始值""不会被正常赋值,会被直接设置为null。 - 核心原因2:虽然你调用了
isNullOrBlank()可空扩展方法,但在部分场景下(比如低版本Kotlin编译器、DataBinding生成的Java代码跨语言调用、API30以上设备误调用Java自带的String.isBlank()成员方法),null调用该方法会触发非空检查抛出空指针。 - 附加问题:你的
nameInitials所有逻辑分支最终都会返回非空字符串,不需要声明为可空类型String?,不必要的可空声明也增加了空指针风险。
修复方案
推荐使用by lazy重写该属性,完全规避空指针问题,同时只做一次计算性能更优:
@Parcelize data class ModelChatEntry( val id: String, val name: String? ): BaseModel, Parcelable { // 忽略序列化,反序列化后首次访问自动重新计算 @IgnoredOnParcel val nameInitials: String by lazy { name?.takeIf { it.isNotBlank() }?.let { nameStr -> val splits = nameStr.split(" ") when { splits.size >= 2 -> "${splits[0].first()} ${splits[1].first()}" nameStr.isNotEmpty() -> nameStr.first().toString() else -> "-" } } ?: "-" } }
如果需要保留原有自定义getter写法,可以修改为显式判空:
var nameInitials: String = "" get() { // 先显式判断null,避免isNullOrBlank的兼容问题 if (field.isBlank() || field == null) { field = name?.takeIf { it.isNotBlank() }?.let { nameStr-> val splits = nameStr.split(" ") when { splits.size > 1 -> "${splits[0].first()} ${splits[1].first()}" nameStr.isNotEmpty() -> nameStr.first().toString() else -> "-" } }?:"-" } return field }
布局文件不需要做任何修改,即可正常绑定使用。
内容的提问来源于stack exchange,提问作者Naresh NK
相关产品推荐
相关产品推荐

