Probieren Sie Ressourcen in Kotlin aus

147

Als ich versuchte, ein Äquivalent eines Java try-Codes mit Ressourcen in Kotlin zu schreiben , funktionierte es bei mir nicht.

Ich habe verschiedene Variationen der folgenden ausprobiert:

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

Aber beides funktioniert nicht.

Weiß jemand, was stattdessen verwendet werden soll? Anscheinend hat die Kotlin-Grammatik keine Definition für ein solches Konstrukt, aber vielleicht fehlt mir etwas. Es definiert die Grammatik für den Try-Block wie folgt:

try : "try" block catchBlock* finallyBlock?;
Alex
quelle

Antworten:

219

Es gibt eine Funktion usein kotlin stdlib ( src ).

Wie man es benutzt:

OutputStreamWriter(r.getOutputStream()).use {
    // by `it` value you can get your OutputStreamWriter
    it.write('a')
}
user2235698
quelle
3
Ich liebe Erweiterungsmethoden so sehr. So viele Dinge, die Sie tun können und keine zusätzlichen Sprachfunktionen benötigen.
Kirill Rakhman
20
Hinzu kommt, dass es tatsächlich eine Erweiterungseigenschaft gibt, um auch eine zu erhalten OutputStreamWriter:r.outputStream.writer.use { ... }
Damian Wieczorek
3
Link zum Referenzdokument, das die useErweiterung demonstriert : kotlinlang.org/docs/reference/…
Javaru
1
Wie kann ich Multi "Use" besser nutzen? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Ponomarenko Oleh
43

TL; DR: Keine spezielle Syntax, nur eine Funktion

Kotlin hat dafür im Gegensatz zu Java keine spezielle Syntax. Stattdessen wird Try-with-Resources als Standardbibliotheksfunktion angeboten use.

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

Die useImplementierungen

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

Diese Funktion ist als generische Erweiterung für alle Closeable?Typen definiert. Closeableist Javas Schnittstelle , die das Testen mit Ressourcen ab Java SE7 ermöglicht .
Die Funktion nimmt eine Funktionsliteral , blockdie in einem ausgeführt wird try. Das gleiche wie mit Try-mit-Ressourcen in Java, der Closeablewird geschlossen in einemfinally .

Auch Fehler im Inneren blockführen zu closeAusführungen, bei denen mögliche Ausnahmen buchstäblich "unterdrückt" werden, indem sie einfach ignoriert werden. Dies unterscheidet sich von Try-with-Resources , da solche Ausnahmen in der Java -Lösung angefordert werden können.

Wie man es benutzt

Die useErweiterung ist für jeden CloseableTyp verfügbar , dh für Streams, Reader usw.

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

Der Teil in geschweiften Klammern ist , was wird blockin use(a Lambda wird hier als Argument übergeben). Nachdem der Block fertig ist, können Sie sicher sein, dass FileInputStreamer geschlossen wurde.

s1m0nw1
quelle
16

Bearbeiten : Die folgende Antwort gilt weiterhin für Kotlin 1.0.x. Für Kotlin 1.1 wird eine Standardbibliothek unterstützt, die auf Java 8 abzielt, um geschlossene Ressourcenmuster zu unterstützen.

Für andere Klassen, die die "use" -Funktion nicht unterstützen, habe ich die folgenden hausgemachten Versuche mit Ressourcen durchgeführt:

package info.macias.kotlin

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

Dann können Sie es folgendermaßen verwenden:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}
Mario
quelle
1
Dies behandelt Ausnahmen aus der finally-Klausel nicht richtig. Dies ist einer der Gründe, warum Java mit Try-with-Resources ausgestattet wurde. Dies ist nur ein einfacher try/finallyBlock
Nikola Mihajlović
0

Da sich dieser StackOverflow-Beitrag ganz oben in den aktuellen Suchergebnissen für "Kotlin Closeable Example" befindet und dennoch keine der anderen Antworten (noch die offiziellen Dokumente) klar erklärt, wie Closeable(aka java.io.Closeable) erweitert werden soll, dachte ich, ich würde ein Beispiel hinzufügen wie man eine eigene Klasse macht, die sich erweitert Closeable. Es geht so:

import java.io.Closeable

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

Und dann, um es zu benutzen:

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

Sehen Sie dieses Beispiel auf dem Kotlin-Spielplatz hier .

Quuxpluson
quelle