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?;

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')
}

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é.


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

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 .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.