27

当从 Kotlin 调用非可空性注释的 Java 函数时,我们会得到灵活类型的返回值,用感叹号表示,例如String!.

Kotlin 默默地允许将这些灵活的值分配给普通的非空类型,例如String,这可能会在运行时导致 NullPointerExceptions。

我希望获得此类分配的编译器警告或错误。或者,将平台类型视为等同于可空类型(例如String?)。

例如,使用此 Java 代码:

import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

public class NullTest {

    private String maybe() {
        if (SystemClock.elapsedRealtimeNanos() % 2 == 0) {
            return null;
        }
        return "ok";
    }

    public String annotatedNothing()            { return maybe(); }
    @Nullable public String annotatedNullable() { return maybe(); }
    @NonNull  public String annotatedNonNull()  { return "ok"; }

}

...和下​​面的 Kotlin 代码,我想在两个新行上得到错误(见评论):

fun testnulls() {
    val obj = NullTest()

    val nullExact: String  = obj.annotatedNullable() // already gives an error
    val nullMaybe: String? = obj.annotatedNullable()
    val nullInfer          = obj.annotatedNullable()

    val okayExact: String  = obj.annotatedNonNull()
    val okayMaybe: String? = obj.annotatedNonNull()
    val okayInfer          = obj.annotatedNonNull()

    val bareExact: String  = obj.annotatedNothing() // I want a compiler error here
    val bareMaybe: String? = obj.annotatedNothing()
    val bareInfer          = obj.annotatedNothing()

    print("length " + nullExact.length)
    print("length " + nullMaybe.length) // already gives an error
    print("length " + nullInfer.length) // already gives an error

    print("length " + okayExact.length)
    print("length " + okayMaybe.length) // already gives an error
    print("length " + okayInfer.length)

    print("length " + bareExact.length)
    print("length " + bareMaybe.length) // already gives an error
    print("length " + bareInfer.length) // I want a compiler error here
}

关键是这将迫使我添加空检查或!!,确保我至少必须明确说明。

这可能吗?

在这篇2014 JetBrains 博客文章的评论中,当他们引入平台/灵活类型时,听起来他们正计划添加一个选项来警告这些情况,但我无法找到任何进一步的信息。

4

4 回答 4

4

的,如果方法没有@NotNull注解,则可以从 Java 方法的任何分配中获取编译器警告和/或错误@Nullable

如何?:)您必须编写自己的 Idea Custom Inspection 插件

对于任何有足够经验来构建自定义检查插件的人来说,这里有一些有用的链接(我可能会是它的感激用户之一):

  1. Idea插件开发快速入门指南
  2. 所有现有 Idea Kotlin 检查的来源(可能作为现有空安全检查的示例有用)

如果您是熟悉且经验丰富的 Idea 插件开发人员,那么可能不会花费很多时间。否则我不认为你将要达到的结果真的值得你花费时间。

我喜欢你的想法,但是在开发的早期阶段,AFAIKkotlin曾试图实施尽可能完整的空安全检查,结果变成这样,有太多潜在的不安全分配。

ps 如果您最终会构建该检查插件,请告诉我。我个人试图做到这一点,但就我而言,我必须首先了解更多关于 Idea 插件的信息。

于 2017-08-27T17:52:38.963 回答
0

Kotlin文档描述了这种确切的情况:

Java 中的任何引用都可能为空,这使得 Kotlin 对来自 Java 的对象的严格空安全性要求不切实际。Java 声明的类型在 Kotlin 中被特殊处理,称为平台类型。此类类型的空值检查被放宽,因此对它们的安全保证与 Java 中的相同

不幸的是,这意味着在编译期间无法发出警告。一线希望是 Kotlin 至少会阻止 null 在运行时传播。

当我们在平台类型的变量上调用方法时,Kotlin 不会在编译时发出可空性错误,但调用可能会在运行时失败,因为空指针异常或 Kotlin 为防止空值传播而生成的断言

如果我不控制我使用的 Java 库的源代码,我会将所有结果视为可能为空,除非很明显它们不是。

于 2017-08-15T11:30:50.750 回答
0

我做了一些研究,发现了一些有趣的链接。

首先,正如其他人所提到的,Kotlin 开发人员似乎希望避免误报,这里讨论了添加编译时间选项来标记平台类型使用情况: https : //youtrack.jetbrains.com/issue/KTIJ-6891 kotlin 团队似乎不愿意添加。

但是我发现 detekt(kotlin 的静态代码分析工具)的开发人员在添加平台类型使用检测方面存在一个未解决的问题: https ://github.com/detekt/detekt/issues/3603

似乎他们相对接近添加这个。 https://github.com/detekt/detekt/pull/4470/files

所以希望这将帮助开发人员在用户之前抓住那些 NPE。

于 2022-02-07T08:48:04.980 回答
-2

对于非空字符串 -

检查 isEmpty()。您将无法在该方法中传递非空字符串。所以它是类型安全的。

对于空字符串-

您可以在 if 条件中检查 null。

于 2017-09-01T09:06:26.390 回答