I have Dao to return simple object. If object does not exist, Room return null, but Android app have no crashes. Also if I assign that value to non-null variable, no crashes are in app.

Dao:

@Query("SELECT * FROM users WHERE id LIKE :id LIMIT 1")
abstract fun getById(id: Long): User

not crashing code:

doAsync {
    val user: User = userDao.getById(999)   // user 999 not exist, userDao returns null
    uiThread {
        if (user == null) {
            Timber.d("user is $user")   // "user is null" in log
        } else {
            Timber.d("user is ${user.email}")
        }
    }
}

我有两个问题:

  1. How is possible that Room can return Null value as Non-Null variable?
  2. How is possible that code with assign null to Non-Null variable has no crashes?

推荐答案

这一切都是关于Kotlin如何使用Java代码处理边界上的空值.

If you pass null from Java to Kotlin method that require non-null value you will get exception. This is achieved with calls to Intrinsics.checkNotNull function added by Kotlin compiler in beginning of method.

For example:

fun hello(who: String): Unit {
    println ("Hello $who")
}

变成

public final void hello(@NotNull String who) {
    Intrinsics.checkParameterIsNotNull(who, "who");
    String var2 = "Hello " + who;
    System.out.println(var2);
}

从Kotlin调用Java方法时添加了类似的判断.

But in you case you have Kotlin interface and it's implementation in Java generated by Room. So Kotlin compiler can't add checks because it has no control on all implementations of interface. Otherwise it would have to add checks after every call to Kotlin class or interface because it can be implemented in Java, what is bad for performance.

UPD: found similar issue at Room bugtracker https://issuetracker.google.com/issues/112323132. Googler said that this is intended behavior and if you wrote query that can return null value, then you are responsible to mark it as nullable in dao interface.

Kotlin相关问答推荐

Kotlin和JavaFX:绑定行为奇怪

为什么在Spring中,对事务性方法调用的非事务方法调用仍然在事务中运行?

在Kotlin中,我是否可以访问已知的WHEN子句值?

Kotlin-elvis算子don';不使用map.get()

有没有什么方法或算法可以在没有存储的情况下生成唯一的随机数?

kotlin 父类具有依赖于抽象变量的变量

如何在 Android Jetpack Compose 中的画布上绘制一侧加厚的描边?

使用 Compose for Desktop Bundle 文件

KMM:编译失败:意外的 IrType 类型:KIND_NOT_SET

如何使用 Android CameraX 自动对焦

如何在 kotlin @Parcelize 中使用 null

Kotlin 中的部分类委托

零安全的好处

Foo::class.java 和 Foo::javaClass 有什么区别?

如何解决此错误请Kotlin:[Internal Error] java.lang.ExceptionInInitializerError

Android 与 Kotlin - 如何使用 HttpUrlConnection

Spring Boot:更改属性占位符符号

如何获取Kotlin中变量的名称?

在android的默认浏览器 Select 列表中添加我的浏览器?

Dagger +Kotlin 不注入