Попробуй с ресурсами в Котлине

149

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

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

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

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

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

try : "try" block catchBlock* finallyBlock?;
Alex
источник

Ответы:

220

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

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

OutputStreamWriter(r.getOutputStream()).use {
    // by `it` value you can get your OutputStreamWriter
    it.write('a')
}
user2235698
источник
3
Я очень люблю методы расширения. Так много вещей, которые вы можете сделать, и вам не нужны дополнительные языковые функции.
Кирилл Рахман
20
В добавление к этому, на самом деле есть свойство расширения для получения OutputStreamWriter:r.outputStream.writer.use { ... }
Дамиана Вечорека
3
Ссылка на справочный документ, демонстрирующий useрасширение: kotlinlang.org/docs/reference/…
Javaru
1
Как я могу использовать multi "use" лучше? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Пономаренко Олег
44

TL; DR: нет специального синтаксиса, только функция

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

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. То же самое с примеркой с-ресурсами в Java, то Closeableполучает закрыто в finally.

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

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

useРасширение доступно на любом Closeableтипе, то есть потоки, читатели и так далее.

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

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

s1m0nw1
источник
16

Изменить : Следующий ответ все еще действителен для 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)
    }
}
Марио
источник
1
Это не работает должным образом с исключениями, выдаваемыми из предложения finally, что является одной из причин добавления try-with-resources в Java. Это просто простой try/finallyблок
Никола Михайлович
0

Поскольку этот пост в StackOverflow находится в верхней части текущих результатов поиска по запросу «пример закрывающегося котлина», и тем не менее ни один из других ответов (ни официальных документов) четко не объясняет, как его расширить Closeable(иначе java.io.Closeable), я решил добавить пример о том, как сделать свой собственный класс, который расширяется Closeable. Это выглядит так:

import java.io.Closeable

class MyServer : Closeable {
    override fun close() {
        println("hello world")
    }
}

А потом использовать это:

fun main() {
    val s = MyServer()
    s.use {
        println("begin")
    }
    println("end")
}

Смотрите этот пример на игровой площадке Kotlin здесь .

Quuxplusone
источник