Kotlin 1.3带来了一个新功能,即收缩,并且功能require()
与之相关,但看起来与assert()
非常相似。这是他们的KDoc所说的:
require(value: Boolean)
:如果IllegalArgumentException
为假,则抛出value
。
assert(value: Boolean)
:如果AssertionError
为false并且使用-ea JVM选项在JVM上启用了运行时断言,则引发value
。
那么我什么时候应该使用require()
,什么时候应该使用assert()
?
答案 0 :(得分:2)
假设您想要一个函数来计算 n!(阶乘),如下所示:
fun factorial(n: Long): Long {
require(n >= 0) { "Number must no be negative" }
// code
}
在这种情况下,require()
检查传递给该函数的参数的有效性,如果该参数不符合要求,则抛出一个IllegalArgumentException
并用于调试您也有解释性消息。
另一方面,assert()
可以在代码中的任何位置使用,以进行自己的专门检查,如果启用了运行时断言。
也有
如果check(Boolean)
的参数为false,则会抛出IllegalStateException
,
用于检查对象状态。
因此,以上每个内容在代码中都有自己的位置,如果发现有用,可以使用它。
答案 1 :(得分:2)
require
和assert
的工作方式不同。为此,您需要深入研究代码。
assert(condition)
在内部调用其他方法,您可以在其中查看实际代码:
@kotlin.internal.InlineOnly
public inline fun assert(value: Boolean, lazyMessage: () -> Any) {
if (_Assertions.ENABLED) {
if (!value) {
val message = lazyMessage()
throw AssertionError(message)
}
}
}
AFAIK,这与-ea
标志相关;如果-ea
不存在(或被禁用),则assert
将不会引发异常。
因此,它将无法编译:
fun something(string: String?){
assert (string != null)
nonNull(string) // Type mismatch
}
fun nonNull(str: String){}
这是需求的来源。require(condition)
也在后台调用了另一种方法。如果将assert
替换为require
,您会看到智能转换将成功将其转换为非null,因为如果条件失败,可以保证require
会引发异常。
@kotlin.internal.InlineOnly
public inline fun require(value: Boolean, lazyMessage: () -> Any): Unit {
contract {
returns() implies value
}
if (!value) {
val message = lazyMessage()
throw IllegalArgumentException(message.toString())
}
}
仅布尔函数也执行合同,如果合同失败,则调用该方法。
合同是新的,我不确定它们如何工作,但这是我的理解方式:
implies
关键字是infix fun
;它的作用是告诉编译器从方法返回的条件为真。就像我前面提到的示例一样,这有助于自动广播。它实际上并不会导致方法返回(或者至少这是我当前的测试所指向的),但是它是针对编译器的。
它也是可读的:returning implies condition is true
那是联系的一部分:这里总是抛出异常,如您所见。 require
使用if(!value)
,而assert
则检查if(_Assertions.ENABLED && !value)
。
这不是require
的唯一用途。它也可以用于验证参数。即如果您有这样的话:
operator fun get(index: Int) : T {
if (index < 0 || index >= size)
throw IllegalArgumentException("Index out of range")
// return here
}
您可以将其替换为:
operator fun get(index: Int) : T {
require (index >= 0 && index < size) { "Index out of range" }
// return here
}
此功能有很多不同的用途,但这只是一些示例。
这意味着什么:
assert
就像Java中一样;仅在启用断言时触发。使用它不能保证满足条件。 require
始终有效,与VM标志无关这意味着require
可用于帮助编译器进行智能强制转换,并且最好使用assert
来确保参数有效。而且由于它也不管VM标志如何都可以工作,因此可以在调试情况下使用,如forpas所述。如果您要使用Kotlin编写库,则可以使用require
将参数检查替换为手动抛出,并且仍然可以使用。显然,这里假设使用Kotlin 1.3.0,但这并不重要。
并且可以在内部使用以确保智能强制转换能够按预期工作,但是如果不满足条件,则会引发异常。
不过要回答您的问题:
require
,即使该参数正在生产中也是如此。 assert
,并启用-ea
标志。