在 Kotlin 中使用异常作为默认参数

Using exceptions as default arguments in Kotlin

我正在 Kotlin 中编写一个函数来从数据库中检索 T 类型的项目。

如果没有找到匹配结果,用户可以指定要调用的操作,否则会抛出 IllegalArgumentException

fun get(
    ...,
    onNoneFound: () -> T = throw IllegalStateException("No matching results found")
): T {
    ...

    return when (results.size) -> {
        0 -> onNoneFound.invoke()
        1 -> ...
        else -> chooseResult(...)
    }
}

我遇到的问题是,每当调用函数时,似乎 IllegalStateException 在函数体执行之前抛出。

在某种程度上,这是有道理的,我想解决方法可能是:

fun get(
    ...,
    onNoneFound: (() -> T)? = null
): T {
    ...

    return when (results.size) -> {
        0 -> if (onNoneFound == null) {
            throw IllegalArgumentException("No matching results found")
        } else {
            onNoneFound.invoke()
        }
        1 -> ...
        else -> chooseResult(...)
    }
}

我想知道是否有更多 elegant/preferable 解决此问题的方法 - 理想情况下我不必使函数可为空并稍后进行空检查。有没有一种方法可以使用 Kotlin 的默认参数语法来做到这一点?

编辑: 我想到我可以使用 elvis 运算符进行 null 检查,这确实使代码更优雅:

onNoneFound?.invoke() ?: throw IllegalArgumentException("No matching results found")

但我仍然很好奇 Kotlin 是否有内置的方法来执行此操作而无需空值检查。

您不应该直接构建异常。尝试:

fun get(
    ...,
    onNoneFound: () -> T = { throw IllegalStateException("No matching results found") }
): T {
    ...

    return when (results.size) -> {
        0 -> onNoneFound.invoke()
        1 -> ...
        else -> chooseResult(...)
    }
}

问题在于 throw IllegalStateException(...) 是类型 () -> T 的完美表达式,就像它是任何其他类型的表达式一样;但它会立即抛出异常,你想要的是一个 lambda,它会在调用时 抛出异常。这就是 Kotlin 中的 { throw IllegalStateException(...) },因为 Roger Lindsjö 的回答说。