requireNotNull vs确定运算符!在科特林

时间:2018-10-09 09:50:44

标签: kotlin codacy

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

我们是否有任何特定的理由或约定选择一个而不是另一个。据我所知,两者都将引发Exception并阻塞执行流程,除了一个会引发IllegalArgumentException,而另一个会引发NullPointerException。

3 个答案:

答案 0 :(得分:2)

假设您指的是requireNotNull

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

您没有添加任何代码,因此很难帮助您调试。您提到了第三方代码质量工具,但没有提到。我随机发现与您遇到的错误相符的this GH issue。这也是我唯一发现的随时都会使用该确切错误的东西。我可能已经错过了一些内容,但这是涵盖Google热门歌曲的内容,因此我将不再赘述。

问题提到OP通过Codacy使用Detekt,这似乎也与您的环境匹配。

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

但是,您可以使用另一种方式。

是的,使用Objects#requireNonNull是一种选择。但是还有第二个,它使用了null安全运算符,如m0skit0所述。

之所以起作用,是因为如果任何调用为空,则最终结果为空。即这个:

instance.nonNullType.nullable?.nullableChild?.someOtherNullableChild

如果任何可为null的结果为null,则最终结果为null,并且没有其他结果被调用。

现在,考虑到这可能是“检测”中的错误,这似乎是目前最简单的解决方法:

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; DR:

!!requireNotNull的工作方式实际上是相同的,除了requireNotNull是一个方法调用,!!编译为if语句:

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

!!触发UnsafeCallOnNullableType的原因是Detekt中的(可能)错误(假设您直接或间接使用它)。

答案 1 :(得分:0)

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

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

请注意,当defaultValuesettings返回null时,此表达式将返回getValue

最好完全避免使用!!运算符,因为这基本上会破坏对null的任何保护。如果无法做到这一点,我将抛出更全面的异常,而不是依赖于IAE或NPE之类的通用异常,例如:

settings?.getValue("some-setting") ?: throw SettingNotFound("Descriptive message")

答案 2 :(得分:0)

正如您提到的,requireNotNull()引发IllegalArgumentException,而!!引发NullPointerException。如果您想区分开发人员添加的防御性代码和非防御性代码(通过使用!!并不明显),那将很有帮助。

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