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


147

Коли я намагався написати еквівалент tryкоду Java -ресурсів у Котліні, мені це не вийшло.

Я спробував різні варіанти наступного:

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

Але не працює.

Хтось знає, що слід використовувати замість цього? Мабуть, граматика Котліна не має визначення для такої конструкції, але, можливо, мені щось не вистачає. Він визначає граматику для блоку спробу наступним чином:

try : "try" block catchBlock* finallyBlock?;

Відповіді:


219

Є use-функція в kotlin stdlib ( src ).

Як ним користуватися:

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

3
Я так люблю методи розширення. Стільки речей, які ви можете зробити, і немає потреби в додаткових мовних функціях.
Кирило Рахман

20
Додаючи до цього, насправді є властивість розширення, щоб отримати OutputStreamWriterтакож:r.outputStream.writer.use { ... }
Damian Wieczorek

3
Посилання на посилання на документ, який демонструє useрозширення: kotlinlang.org/docs/reference/…
Javaru

1
Як можна краще використовувати багатокористувацьке використання? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Пономаренко Олег

43

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

Котлін, на відміну від Java, не має для цього спеціального синтаксису. Натомість спробувати з ресурсами пропонується як стандартна функція бібліотеки 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який виконується в a try. Те ж саме з приміркою з-ресурсами в Java, то Closeableотримує закрито в finally.

Також невдачі, що трапляються всередині, blockпризводять до closeстрати, де можливі винятки буквально «придушуються» шляхом просто їх ігнорування. Це відрізняється від пробних ресурсів , оскільки такі винятки можна вимагати в рішенні Java .

Як ним користуватися

useРозширення є на будь-якому Closeableтипі, тобто потоки, читачі і так далі.

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

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


16

Редагувати : Наступна відповідь все ще діє для Kotlin 1.0.x. Для Kotlin 1.1 існує підтримка стандартної бібліотеки, яка націлена на Java 8 для підтримки шаблону ресурсів, що закриваються.

Для інших класів, які не підтримують функцію "використання", я зробив такі домашні спроби із ресурсами:

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
Це не стосується належним чином винятків, викинутих із остаточного пункту, що є однією з причин того, що в 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")
}

Дивіться цей приклад на майданчику Котлін тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.