require和assert有什么区别?

时间:2018-11-04 09:12:39

标签: kotlin

Kotlin 1.3带来了一个新功能,即收缩,并且功能require()与之相关,但看起来与assert()非常相似。这是他们的KDoc所说的:

require(value: Boolean):如果IllegalArgumentException为假,则抛出value

assert(value: Boolean):如果AssertionError为false并且使用-ea JVM选项在JVM上启用了运行时断言,则引发value

那么我什么时候应该使用require(),什么时候应该使用assert()

2 个答案:

答案 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)

requireassert的工作方式不同。为此,您需要深入研究代码。

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标志。