Essayer avec des ressources à Kotlin

1. Introduction

Les langages gérés, tels que ceux ciblant la JVM, gèrent automatiquement la ressource la plus courante: la mémoire.

Cependant, nous devons gérer toutes sortes de ressources, pas seulement la mémoire: fichiers, connexions réseau, flux, fenêtres, etc. Et, tout comme la mémoire, celles-ci doivent être libérées lorsqu'elles ne sont plus nécessaires.

Dans cet article, nous allons voir comment les ressources peuvent être gérées automatiquement dans Kotlin et en quoi elles diffèrent de la construction try-with-resources de Java.

Si vous souhaitez ignorer la théorie, passez directement à l'exemple.

2. Gestion automatique des ressources

Nous pouvons distinguer trois phases différentes lorsque l'on travaille avec des ressources en Java (pseudocode):

resource = acquireResource() try { useResource(resource) } finally { releaseResource(resource) } 

Si le langage ou la bibliothèque est responsable de la libération de la ressource (la partie finale ), nous l'appelons la gestion automatique des ressources. Une telle fonctionnalité nous évite d'avoir à nous souvenir de libérer une ressource.

De plus, étant donné que la gestion des ressources est généralement liée à une étendue de bloc, si nous traitons plusieurs ressources en même temps, elles seront toujours libérées dans le bon ordre.

En Java, les objets qui contiennent une ressource et qui sont éligibles pour la gestion automatique des ressources implémentent une interface spécifique: fermable pour les ressources liées aux E / S et fermable automatiquement .

De plus, Java 7 a modernisé l' interface Closeable préexistante pour étendre AutoCloseable .

Par conséquent, Kotlin a le même concept de détenteurs de ressources: c'est-à-dire des objets implémentant soit Closeable soit AutoCloseable .

3. La fonction d' utilisation dans Kotlin

Pour gérer automatiquement les ressources, certains langages ont une construction dédiée: Java 7 a introduit try-with-resources, par exemple, tandis que C # a le mot-clé using .

Parfois, ils nous proposent un modèle, comme RAII en C ++. Dans certains autres cas, ils nous donnent une méthode de bibliothèque.

Kotlin entre dans cette dernière catégorie.

De par sa conception, il n'a pas de construction de langage semblable à try-with-resources en Java.

Au lieu de cela, nous pouvons trouver une méthode d'extension appelée use dans sa bibliothèque standard.

Nous l'examinerons en détail plus tard. Pour l'instant, nous avons juste besoin de savoir que chaque objet détenteur de ressources a la méthode use que nous pouvons appeler.

3.1. Comment l'utiliser

Un exemple simple:

val writer = FileWriter("test.txt") writer.use { writer.write("something") }

Nous pouvons invoquer la fonction use sur n'importe quel objet qui implémente AutoCloseable ou Closeable , tout comme avec try-with-resources en Java.

La méthode prend une expression lambda, l'exécute et supprime la ressource de (en appelant close () dessus) chaque fois que l'exécution quitte le bloc, soit normalement, soit avec une exception.

Donc, dans ce cas, après utilisation, l' écrivain n'est plus utilisable, car Kotlin l'a automatiquement fermé.

3.2. Une forme plus courte

Dans l'exemple ci-dessus, pour plus de clarté, nous avons utilisé une variable appelée writer , créant ainsi une fermeture.

Cependant, use accepte une expression lambda avec un seul paramètre - l'objet contenant la ressource:

FileWriter("test.txt") .use { w -> w.write("something") }

À l'intérieur du bloc, nous pouvons également utiliser la variable implicite it :

FileWriter("test.txt") .use { it.write("something") }

Ainsi, comme nous pouvons le voir, nous n'avons pas à donner à l'objet un nom explicite. Cependant, il est généralement préférable d'être clair plutôt que d'écrire du code trop concis.

3.3. La définition de l' utilisation ()

Regardons la définition de la fonction d' utilisation dans Kotlin, telle qu'elle se trouve dans sa bibliothèque standard:

public inline fun  T.use(block: (T) -> R): R

On peut voir, dans le part, cette utilisation est définie comme une fonction d'extension sur l' interface fermable de Java .

Plus d'informations sur les méthodes d'extension peuvent être trouvées dans notre article d'introduction.

Bien sûr, la fonction d' utilisation est documentée dans le cadre de la bibliothèque standard de Kotlin.

3.4. Fermeture vs fermeture automatique

Si nous prêtons plus d'attention à l'exemple de la section précédente, nous pouvons voir que la signature de la fonction d' utilisation est définie uniquement sur l' interface Closeable . En effet, la bibliothèque standard de Kotlin cible Java 6.

Dans les versions Java antérieures à 7, AutoCloseable n'existait pas et, bien sûr, Closeable ne l' étendait pas.

En pratique, les classes qui implémentent AutoCloseable mais pas Closeable sont rares. Pourtant, nous pouvons rencontrer l'un d'entre eux.

Dans ce cas, nous n'avons qu'à ajouter une dépendance aux extensions de Kotlin pour Java 7, 8 ou quelle que soit la version que nous ciblons:

 org.jetbrains.kotlin kotlin-stdlib-jdk8 

La dernière version de la dépendance est disponible sur Maven Central.

Cela nous donne une autre fonction d'extension d' utilisation définie sur l' interface AutoCloseable :

public inline fun  T.use(block: (T) -> R): R

4. Conclusion

Dans ce tutoriel, nous avons vu comment une simple fonction d'extension dans la bibliothèque standard de Kotlin est tout ce dont nous avons besoin pour gérer automatiquement toutes sortes de ressources connues de la JVM.

L'implémentation de tous ces exemples et extraits de code se trouve dans le projet GitHub.