我们有一个基于Kotlin的应用程序,最近我们添加了第三方代码质量工具(Codacy中的Detekt)。但是,我们开始遇到UnsafeCallOnNullableType错误。 我们发现可行的方法是在所有可能为null的参数上添加requireNotNull检查。当前,我们正在使用确定运算符(!!)
我们是否有任何特定的理由或约定选择一个而不是另一个。据我所知,两者都将引发Exception并阻塞执行流程,除了一个会引发IllegalArgumentException,而另一个会引发NullPointerException。
答案 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)
如果您确实需要验证每个步骤,则只需要在所有地方保留空检查
!!
和requireNotNull
的工作方式实际上是相同的,除了requireNotNull
是一个方法调用,!!
编译为if语句:
if(whatever == null) {
Intrinsics.throwNpe();
}
!!
触发UnsafeCallOnNullableType
的原因是Detekt中的(可能)错误(假设您直接或间接使用它)。
答案 1 :(得分:0)
根据我的经验,值可为空时的最佳实践是使用?
和?:
运算符,并在值为空时提供替代方法(如果可用),例如:
settings?.getValue("some-setting") ?: defaultValue
请注意,当defaultValue
或settings
返回null时,此表达式将返回getValue
。
最好完全避免使用!!
运算符,因为这基本上会破坏对null的任何保护。如果无法做到这一点,我将抛出更全面的异常,而不是依赖于IAE或NPE之类的通用异常,例如:
settings?.getValue("some-setting") ?: throw SettingNotFound("Descriptive message")
答案 2 :(得分:0)
正如您提到的,requireNotNull()
引发IllegalArgumentException,而!!
引发NullPointerException。如果您想区分开发人员添加的防御性代码和非防御性代码(通过使用!!
并不明显),那将很有帮助。
但是,使用requireNotNull()
的最大好处是使用带有lazyMessage参数的函数。这样,您的开发人员可以向异常添加更多有意义的消息,这有助于调试