requireNotNull 与 sure 运算符!!在科特林
requireNotNull vs sure operator !! in Kotlin
我们有一个基于 Kotlin 的应用程序,最近我们添加了第三方代码质量工具(Codacy 中的 Detekt)。但是,我们开始面临 UnsafeCallOnNullableType 错误。
我们发现可行的方法是对所有可能为 null 的参数添加 requireNotNull 检查。目前,我们正在使用确定运算符 (!!)
我们是否有任何特定的理由或惯例来选择一个而不是另一个。据我所知,两者都会抛出异常并阻止执行流程,除了一个会抛出 IllegalArgumentException 而另一个会抛出 NullPointerException。
根据我的经验,当值可为 null 时,最佳做法是使用 ?
和 ?:
运算符,并在值为 null 时提供替代方案(如果可用),例如:
settings?.getValue("some-setting") ?: defaultValue
请注意,当 settings
或 getValue
return 为空时,此表达式将 return defaultValue
。
最好尽量避免使用 !!
运算符,因为这基本上会破坏任何针对空值的保护。当这不可能时,我会抛出一个更全面的异常,而不是依赖像 IAE 或 NPE 这样的通用异常,例如:
settings?.getValue("some-setting") ?: throw SettingNotFound("Descriptive message")
requireNotNull
,假设您指的是 Objects#requireNonNull
,是一个 Java 方法,它等同于 !!
,但有一个不同的例外。
您没有添加任何代码,所以帮助您调试有点困难。您提到了第三方代码质量工具,但没有提到是哪个。我偶然发现 this GH issue 与您遇到的错误相匹配。这也是我能找到的唯一会在任何时候使用该确切错误的东西。我可能漏掉了一些,但它涵盖了 Google 的热门歌曲,所以我要放弃它。
如果您使用的是 Detekt,这是一个已报告的错误。 IntelliJ 甚至建议使用 !!
。
但是,您可以采用其他方式。
是的,使用 Objects#requireNonNull
是一种选择。不过还有第二个,它使用空安全运算符,正如 m0skit0 提到的那样。
之所以可行,是因为如果调用的任何内容为空,则最终结果为空。 IE。这个:
instance.nonNullType.nullable?.nullableChild?.someOtherNullableChild
如果有一个可空的为null,则最终结果为null,调用其他none个
现在,考虑到这可能是检测中的错误,这似乎是目前最简单的解决方法:
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 中的一个(可能的)错误。不过,这两个选项都是同一事物的语法糖:如果变量为 null,则抛出 NPE。
如您所述,requireNotNull()
抛出 IllegalArgumentException,!!
抛出 NullPointerException。如果您想区分开发人员添加的防御代码与未防御代码(通过使用 !!
不是很明显),这可能会有所帮助。
然而,使用 requireNotNull()
的更大好处是使用带有 lazyMessage 参数的函数。这样您的开发人员就可以向异常添加更多有意义的消息,这有助于调试
我们有一个基于 Kotlin 的应用程序,最近我们添加了第三方代码质量工具(Codacy 中的 Detekt)。但是,我们开始面临 UnsafeCallOnNullableType 错误。 我们发现可行的方法是对所有可能为 null 的参数添加 requireNotNull 检查。目前,我们正在使用确定运算符 (!!)
我们是否有任何特定的理由或惯例来选择一个而不是另一个。据我所知,两者都会抛出异常并阻止执行流程,除了一个会抛出 IllegalArgumentException 而另一个会抛出 NullPointerException。
根据我的经验,当值可为 null 时,最佳做法是使用 ?
和 ?:
运算符,并在值为 null 时提供替代方案(如果可用),例如:
settings?.getValue("some-setting") ?: defaultValue
请注意,当 settings
或 getValue
return 为空时,此表达式将 return defaultValue
。
最好尽量避免使用 !!
运算符,因为这基本上会破坏任何针对空值的保护。当这不可能时,我会抛出一个更全面的异常,而不是依赖像 IAE 或 NPE 这样的通用异常,例如:
settings?.getValue("some-setting") ?: throw SettingNotFound("Descriptive message")
requireNotNull
,假设您指的是 Objects#requireNonNull
,是一个 Java 方法,它等同于 !!
,但有一个不同的例外。
您没有添加任何代码,所以帮助您调试有点困难。您提到了第三方代码质量工具,但没有提到是哪个。我偶然发现 this GH issue 与您遇到的错误相匹配。这也是我能找到的唯一会在任何时候使用该确切错误的东西。我可能漏掉了一些,但它涵盖了 Google 的热门歌曲,所以我要放弃它。
如果您使用的是 Detekt,这是一个已报告的错误。 IntelliJ 甚至建议使用 !!
。
但是,您可以采用其他方式。
是的,使用 Objects#requireNonNull
是一种选择。不过还有第二个,它使用空安全运算符,正如 m0skit0 提到的那样。
之所以可行,是因为如果调用的任何内容为空,则最终结果为空。 IE。这个:
instance.nonNullType.nullable?.nullableChild?.someOtherNullableChild
如果有一个可空的为null,则最终结果为null,调用其他none个
现在,考虑到这可能是检测中的错误,这似乎是目前最简单的解决方法:
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 中的一个(可能的)错误。不过,这两个选项都是同一事物的语法糖:如果变量为 null,则抛出 NPE。
如您所述,requireNotNull()
抛出 IllegalArgumentException,!!
抛出 NullPointerException。如果您想区分开发人员添加的防御代码与未防御代码(通过使用 !!
不是很明显),这可能会有所帮助。
然而,使用 requireNotNull()
的更大好处是使用带有 lazyMessage 参数的函数。这样您的开发人员就可以向异常添加更多有意义的消息,这有助于调试