当前位置:网站首页>又被 Kotlin 语法糖坑惨的一天
又被 Kotlin 语法糖坑惨的一天
2022-06-30 11:29:00 【锐湃】
源起是同事的一次反馈,在提测期间报了一个 Kotlin.Lazy 的空指针异常,Lazy 的定义如下:
class TestA{
...
val xxxx:Service? by lazy{
xxxService()
}
...
}
看起来很平常的 by lazy 为何会报空指针?在深入 lazy 源码查看的时候,并未发现任何可疑点,由于当时的代码逻辑涉及到并发调用,也查看了 by lazy 的初始化,默认实现是 SynchronizedLazyImpl,已经做了线程安全操作。
为了避免太多代码的干扰,我们将涉及到 by lazy 使用的地方都拷贝到了一个 Test 类中,然后通过 Decompile 反编译成 Java 代码来查看是否是 kotlin 的问题。
Kotlin 代码如下:
class TestA {
init {
....
initView()
}
private fun initView() {
// 调用 Service 方法
service?.getName()
}
private val service: AService? by lazy {
AService()
}
}
反编译后的 Java 代码:
public final class TestA {
private final Lazy service$delegate;
private final void initView() {
// 1、获取 service 实例
AService var10000 = this.getService();
if (var10000 != null) {
var10000.getName();
}
}
private final AService getService() {
Lazy var1 = this.service$delegate;
Object var3 = null;
// 2、调用 Lazy 的 getValue 方法
.return (AService)var1.getValue();
}
public TestA() {
this.initView();
// 3、初始化 Lazy 实例
.this.service$delegate = LazyKt.lazy((Function0)null.INSTANCE);
}
}
通过代码的反编译立马查到问题:
1. 在 TestA 的构造方法中,先执行 initView 方法获取 AService 的实例。
2. 但 getService 方法中的 Lazy 还没有初始化,却直接调用了 getValue 方法触发空指针异常。
3. 在 initView 结束之后再做 Lazy 的初始化,这时候已经晚了,异常已经出现了。
那如何解决这问题呢?只需将 by lazy 提到了 init 代码块的前面,如下:
class TestA {
private val service: AService? by lazy {
AService()
}
init {
initView()
}
...
}
反编译结果:
public final class TestA {
private final Lazy service$delegate;
....
public TestA() {
// 1、初始化 Lazy 实例
.this.service$delegate = LazyKt.lazy((Function0)null.INSTANCE);
// 2、再调用 getService 方法
.this.initView();
}
}
1. 构造终于是先初始化 Lazy 对象。
2. 再调用 initView 方法,这时候方法内的 Lazy.getValue 就能被正常调用了。
是不是有点违背常识?为什么在方法里调用一个变量还会涉及到变量放置的位置,Kotlin 这高级语法糖恐怕连 C 都不如吧(嘲笑一番,哈哈)。
那 Kotlin 真的没有对其做语法检查吗?其实是有的,我改变下代码给大家看下:
IDE 会提示当前 service 未初始化,「但该提示仅限在 init 代码块中调用 lazy 的时候提示,如果在 init 中调用一个中间方法,然后再从中间方法调用 lazy,该提示校验将会失效」。
又被 Kotlin 语法糖坑惨的一天!!!
作者有个置顶,一起放上学习~
边栏推荐
- [revisiting the classic C language] ~x,%c,%d,%x, etc. in C language, the role of the address character in C language, and the consortium in C language
- “新数科技”完成数千万元A+轮融资,造一体化智能数据库云管理平台
- 10天学会flutter DAY10 flutter 玩转 动画与打包
- 缓存雪崩和缓存穿透解决方案
- If it is not listed again, Kuangshi technology will not be able to endure
- Goto statement jump uninitialized variable: c2362
- Webview,ScrollView滑动冲突咋整
- koa - 洋葱模型浅析
- 一瓶水引发的“战争”
- AMS source code analysis
猜你喜欢
科普達人丨漫畫圖解什麼是eRDMA?
Dameng data rushes to the scientific innovation board, or becomes the "first share of domestic database" in the A-share market
Database connection pool Druid
谁还记得「张同学」?
R语言去重操作unique duplicate filter
Alibaba cloud database represented by polardb ranks first in the world
HMS Core音频编辑服务3D音频技术,助力打造沉浸式听觉盛宴
一个悄然崛起的国产软件,低调又强大!
10 reasons for system performance failure
数字化不是试出来,而是蹚出来的|行知数字中国 × 富士康史喆
随机推荐
How to analyze native crash through GDB
Database connection pool Druid
R语言去重操作unique duplicate filter
数据库 级联操作
数据库 自动增长
QT embeds the sub QT program window into the current program
TypeScript ReadonlyArray(只读数组类型) 详细介绍
Dameng data rushes to the scientific innovation board, or becomes the "first share of domestic database" in the A-share market
相对位置编码Transformer的一个理论缺陷与对策
wallys/3×3 MIMO 802.11ac Mini PCIe Wi-Fi Module, QCA9880, 2,4GHz / 5GHzDesigned for Enterprise
国内首批!阿里云云原生数据湖产品通过信通院评测认证
How harmful are these "unreliable" experiences in the postgraduate entrance examination?
线下门店为什么要做新零售?
1175. prime permutation
Introduction to game theory
Esp32-c3 introductory tutorial basic part ⑪ - reading and writing non-volatile storage (NVS) parameters
EMC-浪涌
暑假学习记录
学习redis实现分布式锁—–自己的一个理解
led背光板的作用是什麼呢?