Попытка использования ресурсов в Котлине

Когда я попытался написать эквивалент Java try -с-ресурсов код в Котлин, он не работает для меня.

Я пробовал разные варианты следующего:

try (writer = OutputStreamWriter(r.getOutputStream())) {
    // ...
}

Но ни один не работает.

Кто-нибудь знает, что следует использовать вместо этого? Очевидно, у грамматики Котлина нет определения для такой конструкции, но, возможно, я что-то упустил. Он определяет грамматику для блока try следующим образом:

try : "try" block catchBlock* finallyBlock?;

Ответ 1

В kotlin stdlib есть use -функция (src).

Как использовать его:

OutputStreamWriter(r.getOutputStream()).use {
    // by `it` value you can get your OutputStreamWriter
    it.write('a')
}

Ответ 2

TL; DR

Нет специального синтаксиса, но use функцию

В отличие от Java, Kotlin не имеет специального синтаксиса для этого. Вместо этого попробуйте-с-ресурсами, предлагается в качестве стандартной функции библиотеки use.

FileInputStream("filename").use { fis -> //or implicit 'it'
   //use stream here
} 

Реализация use

@InlineOnly
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var closed = false
    try {
        return block(this)
    } catch (e: Exception) {
        closed = true
        try {
            this?.close()
        } catch (closeException: Exception) {
        }
        throw e
    } finally {
        if (!closed) {
            this?.close()
        }
    }
}

Эта функция определяется как общее расширение для всех Closeable? типы. Closeable является интерфейсом Java, который позволяет попробовать ресурсы с Java SE7.
Функция принимает функциональный литеральный block который выполняется в try. Как и в случае с try-with-resources в Java, Closeable закрывается в finally.

Также сбои, происходящие внутри block приводят к выполнению при close, где возможные исключения буквально "подавляются", просто игнорируя их. Это отличается от try-with-resources, потому что такие исключения могут быть запрошены в решении Java.

Как это использовать

Расширение use доступно для любого типа Closeable, т. Closeable, читателей и т.д.

FileInputStream("filename").use {
   //use your stream by referring to 'it' or explicitly give a name.
} 

Часть в фигурных скобках, что становится block в use (лямбда передается в качестве аргумента здесь). После того, как блок сделан, вы можете быть уверены, что FileInputStream был закрыт.

Ответ 3

Изменить: Следующий ответ все еще действителен для Kotlin 1.0.x. Для Kotlin 1.1 существует поддержка стандартной библиотеки, предназначенной для Java 8, для поддержки шаблона закрываемых ресурсов.

Для других классов, которые не поддерживают функцию "use", я сделал следующую самодельную попытку с ресурсами:

package info.macias.kotlin

inline fun <T:AutoCloseable,R> trywr(closeable: T, block: (T) -> R): R {
    try {
        return block(closeable);
    } finally {
        closeable.close()
    }
}

Тогда вы можете использовать его следующим образом:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}