Essayer avec des ressources à Kotlin

148

Quand j'ai essayé d'écrire un équivalent d'un trycode Java avec ressources dans Kotlin, cela n'a pas fonctionné pour moi.

J'ai essayé différentes variantes de ce qui suit:

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

Mais ni l'un ni l'autre ne fonctionne.

Quelqu'un sait-il ce qui devrait être utilisé à la place? Apparemment, la grammaire de Kotlin n'a pas de définition pour une telle construction, mais il me manque peut-être quelque chose. Il définit la grammaire du bloc try comme suit:

try : "try" block catchBlock* finallyBlock?;
Alex
la source

Réponses:

219

Il y a une usefonction dans kotlin stdlib ( src ).

Comment l'utiliser:

OutputStreamWriter(r.getOutputStream()).use {
    // by `it` value you can get your OutputStreamWriter
    it.write('a')
}
user2235698
la source
3
J'aime tellement les méthodes d'extension. Tant de choses que vous pouvez faire et pas besoin de fonctionnalités linguistiques supplémentaires.
Kirill Rakhman
20
En plus de cela, il y a en fait une propriété d'extension pour obtenir un OutputStreamWriteraussi:r.outputStream.writer.use { ... }
Damian Wieczorek
3
Lien vers le document de référence qui démontre l' useextension: kotlinlang.org/docs/reference/…
Javaru
1
Comment puis-je mieux utiliser le multi «usage»? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Ponomarenko Oleh
44

TL; DR: Pas de syntaxe spéciale, juste une fonction

Kotlin, contrairement à Java, n'a pas de syntaxe spéciale pour cela. Au lieu de cela, try-with-resources est proposé comme fonction de bibliothèque standard use.

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

Les useimplémentations

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

Cette fonction est définie comme une extension générique sur tous les Closeable?types. Closeableest l' interface de Java qui permet d' essayer avec des ressources à partir de Java SE7 .
La fonction prend une fonction littérale blockqui est exécutée dans un fichier try. Comme avec try-with-resources en Java, le Closeablese ferme dans unfinally .

Les échecs qui se produisent à l'intérieur blockmènent également à des closeexécutions, où les exceptions possibles sont littéralement "supprimées" en les ignorant simplement. Ceci est différent de try-with-resources , car de telles exceptions peuvent être demandées dans la solution Java .

Comment l'utiliser

L' useextension est disponible sur n'importe quel Closeabletype, c'est-à-dire les flux, les lecteurs, etc.

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

La partie entre accolades est ce qui devient blockin use(un lambda est passé comme argument ici). Une fois le blocage terminé, vous pouvez être sûr qu'il FileInputStreama été fermé.

s1m0nw1
la source
16

Edit : La réponse suivante est toujours valable pour Kotlin 1.0.x. Pour Kotlin 1.1, il existe une prise en charge d'une bibliothèque standard qui cible Java 8 pour prendre en charge les modèles de ressources fermables.

Pour les autres classes qui ne prennent pas en charge la fonction "utiliser", j'ai effectué l'essai avec les ressources maison suivant:

package info.macias.kotlin

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

Ensuite, vous pouvez l'utiliser de la manière suivante:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}
Mario
la source
1
Cela ne traite pas correctement les exceptions lancées par la clause finally, ce qui est l'une des raisons pour lesquelles try-with-resources a été ajouté à Java. Ceci est juste un simple try/finallybloc
Nikola Mihajlović
0

Étant donné que cet article de StackOverflow se trouve presque en haut des résultats de recherche actuels pour "kotlin closeable example", et pourtant aucune des autres réponses (ni la documentation officielle) n'explique clairement comment étendre Closeable(aka java.io.Closeable), j'ai pensé ajouter un exemple comment créer votre propre classe qui s’étend Closeable. Ça va comme ça:

import java.io.Closeable

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

Et puis pour l'utiliser:

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

Voir cet exemple dans le Kotlin Playground ici .

Quuxplusone
la source