12

我们有一个基于 Kotlin 的应用程序,最近我们添加了第三方代码质量工具(Codacy 中的 Detekt)。但是,我们开始面临 UnsafeCallOnNullableType 错误。我们发现可行的方法是对所有可能为空的参数添加 requireNotNull 检查。目前,我们正在使用确定运算符 (!!)

我们是否有任何特定的理由或约定来选择其中一个。据我所知,两者都会抛出异常并阻塞执行流程,除了一个会抛出 IllegalArgumentException 而另一个会抛出 NullPointerException。

4

3 回答 3

4

requireNotNull,假设您指的是Objects#requireNonNull,是一个等效于 的Java方法!!,但有一个不同的例外。

您没有添加任何代码,因此很难帮助您进行调试。您提到了第三方代码质量工具,但没有提到。我偶然发现了这个与您遇到的错误相匹配的GH 问题。这也是我能找到的唯一会在任何时候使用该确切错误的东西。我可能错过了一些,但它涵盖了谷歌的热门歌曲,所以我将不再使用它。

如果您使用 Detekt,这是一个报告的错误。!!IntelliJ 甚至建议使用。

但是,您可以通过其他方式进行操作。

是的,使用Objects#requireNonNull是一种选择。不过还有第二个,它使用了 null-safe 运算符,正如 m0skit0 所提到的。

之所以可行,是因为如果调用的任何内容为 null,则最终结果为 null。即:

instance.nonNullType.nullable?.nullableChild?.someOtherNullableChild

如果任何可空的为空,则最终结果为空,其他任何一个都不会被调用。

现在,考虑到这可能是 Detect 中的一个错误,这似乎是目前最简单的解决方法:

whatever.calls.you?.make?.to?.the?.database ?: throw NullPointerException("Something is null");

它还保持变量非空,这意味着您以后不需要空安全调用。elvis 运算符检查是否有任何内容为空,然后引发异常。或者,您可以只使用Objects#requireNotNull

Objects.requireNonNull(whatever.calls.you.make.to.the.database)

如果你真的需要验证每一步,你只需要在任何地方都保持空检查

TL;博士:

!!并且requireNotNull它们的工作方式实际上是相同的,除了requireNotNull方法调用和!!编译为 if 语句:

if(whatever == null) {
    Intrinsics.throwNpe();
}

!!触发的原因UnsafeCallOnNullableType是 Detekt 中的一个(可能的)错误。但是,这两个选项都是同一事物的语法糖:如果变量为空,则抛出 NPE。

于 2018-10-09T16:39:30.823 回答
3

正如您所提到的,requireNotNull()抛出 IllegalArgumentException 并!!抛出 NullPointerException。如果您想区分开发人员添加的防御性代码与未防御代码(通过使用!!is 不是很明显),这可能会有所帮助。

但是,使用的更大好处requireNotNull()是使用带有lazyMessage 参数的函数。这样,您的开发人员可以向异常添加更有意义的消息,这有助于调试

于 2019-12-03T00:28:41.290 回答
1

根据我的经验,当一个值可以为空时,最佳实践是使用??:运算符,并在值为空时提供替代方案(如果可用),例如:

settings?.getValue("some-setting") ?: defaultValue

请注意,此表达式将在或者返回 nulldefaultValue时返回。settingsgetValue

最好尽量避免使用!!运算符,因为这基本上会破坏对空值的任何保护。如果这是不可能的,我会抛出一个更全面的异常,而不是依赖 IAE 或 NPE 等通用异常,例如:

settings?.getValue("some-setting") ?: throw SettingNotFound("Descriptive message")
于 2018-10-09T09:57:33.323 回答