Wypróbuj z zasobami w Kotlinie

147

Kiedy próbowałem napisać odpowiednik trykodu Java z zasobami w Kotlinie, nie zadziałał.

Wypróbowałem różne warianty następujących:

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

Ale to nie działa.

Czy ktoś wie, czego zamiast tego użyć? Najwyraźniej gramatyka Kotlina nie ma definicji takiej konstrukcji, ale może czegoś mi brakuje. Definiuje gramatykę bloku try w następujący sposób:

try : "try" block catchBlock* finallyBlock?;
Alex
źródło

Odpowiedzi:

219

W usekotlin stdlib ( src ) jest -funkcja .

Jak tego użyć:

OutputStreamWriter(r.getOutputStream()).use {
    // by `it` value you can get your OutputStreamWriter
    it.write('a')
}
user2235698
źródło
3
Bardzo kocham metody rozszerzające. Tak wiele rzeczy możesz zrobić i nie potrzebujesz dodatkowych funkcji językowych.
Kirill Rakhman
20
Do tego dochodzi jeszcze właściwość rozszerzenia do uzyskania OutputStreamWriter:r.outputStream.writer.use { ... }
Damian Wieczorek
3
Link do dokumentu referencyjnego, który demonstruje userozszerzenie: kotlinlang.org/docs/reference/…
Javaru
1
W jaki sposób mogę lepiej wykorzystać funkcję wielokrotnego użytku? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Ponomarenko Oleh
43

TL; DR: Brak specjalnej składni, tylko funkcja

Kotlin w przeciwieństwie do Javy nie ma do tego specjalnej składni. Zamiast tego próbuj z zasobami jest oferowana jako standardowa funkcja biblioteki use.

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

W useimplementacje

@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()
        }
    }
}

Ta funkcja jest zdefiniowana jako ogólne rozszerzenie dla wszystkich Closeable?typów. Closeablejest interfejsem Java, który umożliwia wypróbowanie zasobów od wersji Java SE7 .
Funkcja przyjmuje literał funkcji, blockktóry jest wykonywany w pliku try. Podobnie jak w przypadku try-with-resources w Javie, Closeablezostaje zamknięty w pliku finally.

Również awarie występujące w środku blockprowadzą do closeegzekucji, w których możliwe wyjątki są dosłownie „tłumione” poprzez ich ignorowanie. To różni się od try-with-zasobów , ponieważ takie wyjątki mogą być wymagane w Java rozwiązanie „s.

Jak tego użyć

useRozszerzenie jest dostępne na każdym Closeablerodzaju, czyli strumienie, czytelnicy i tak dalej.

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

Część w nawiasach klamrowych jest tym, co staje się blockw use(tutaj jako argument jest przekazywana lambda). Po wykonaniu blokady możesz być pewien, że FileInputStreamzostała zamknięta.

s1m0nw1
źródło
16

Edycja : Poniższa odpowiedź jest nadal ważna dla Kotlin 1.0.x. Kotlin 1.1 obsługuje standardową bibliotekę, która jest przeznaczona dla języka Java 8 w celu obsługi zamykanego wzorca zasobów.

W przypadku innych klas, które nie obsługują funkcji „use”, wykonałem następujące domowe próby z zasobami:

package info.macias.kotlin

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

Następnie możesz go użyć w następujący sposób:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}
Mario
źródło
1
Nie radzi sobie to właściwie z wyjątkami wyrzucanymi z klauzuli last, co jest jednym z powodów, dla których try-with-resources został dodany do Javy. To tylko prosty try/finallyblok
Nikola Mihajlović
0

Ponieważ ten post StackOverflow znajduje się blisko początku bieżących wyników wyszukiwania hasła „przykład do zamknięcia kotlin”, a żadna z pozostałych odpowiedzi (ani oficjalnej dokumentacji) nie wyjaśnia jasno, jak rozszerzyć Closeable(czyli java.io.Closeable), pomyślałem, że dodam przykład jak stworzyć własną klasę, która się rozszerza Closeable. To wygląda tak:

import java.io.Closeable

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

A następnie, aby go użyć:

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

Zobacz ten przykład na placu zabaw Kotlin tutaj .

Quuxplusone
źródło