我应该在 Kotlin 中使用 Closable.use{...} 处理异常吗?

use*_*013 6 kotlin

根据来源Closable.use,如果发生错误,就会抛出异常。

public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var exception: Throwable? = null
    try {
        return block(this)
    } catch (e: Throwable) {
        exception = e
        throw e
    } finally {
        when {
            apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)
            this == null -> {}
            exception == null -> close()
            else ->
                try {
                    close()
                } catch (closeException: Throwable) {
                    // cause.addSuppressed(closeException) // ignored here
                }
        }
    }
Run Code Online (Sandbox Code Playgroud)

在 的大多数示例中Closable.use,不使用 try-catch,如下所示。为什么不需要错误处理?安全吗?

    BufferedReader(FileReader("test.file")).use { return it.readLine() }
Run Code Online (Sandbox Code Playgroud)

Ten*_*r04 7

这条线

 BufferedReader(FileReader("test.file")).use { return it.readLine() }
Run Code Online (Sandbox Code Playgroud)

不安全。读取和关闭读取器都可能抛出 IOException,但不是 RuntimeException(由编程错误引起)。这意味着让它们不被捕获会使您的应用程序因您无法控制的事情而崩溃。

由于 Kotlin 没有检查异常,因此编译器不会就此发出警告。为了安全地执行此操作,您需要将其包装在 try/catch 中。如果您想以不同于关闭错误的方式处理读取错误,则需要具有内部和外部 try/catch 语句:

try { 
    BufferedReader(FileReader("test.file")).use { 
        try {
            return it.readLine()
        catch (e: IOException) {
            println("Failed to read line")
        }
    }
} catch (e: IOException) {
    println("Failed to close reader")
}
Run Code Online (Sandbox Code Playgroud)

或者包装整个事情并提取任何被抑制的异常,但是区分它们很麻烦:

try {
    BufferedReader(FileReader("test.file")).use { return it.readLine() }
} catch (e: IOException) {
    val throwables = listOf(e, *e.suppressed)
    for (throwable in throwables)
        println(throwable.message)
}
Run Code Online (Sandbox Code Playgroud)

但实际上,您可能不会对各种 IOException 做出不同的反应,因此您可以将一个 try/catch 放在外面。