Présentation du langage Kotlin
Pourquoi Kotlin ?
Kotlin est un langage de programmation à la fois orienté objet et fonctionnel. Il est conçu principalement pour être compilé pour la machine virtuelle Java (JVM). Ainsi, il offre une compatibilité complète avec le langage Java et les autres langages de la JVM comme Groovy et Scala.
Les développeurs chez JetBrains avaient besoin d’une alternative à Java permettant de coder plus rapidement tout en garantissant une qualité de code supérieure. Alors, Kotlin a été créé comme un langage concis, sûr et pragmatique.
Kotlin offre plusieurs avantages, parmi lesquels se trouvent les suivants :
-
Langage statiquement typé : comme Java, Kotlin est aussi un langage de programmation statiquement typé. Les types de variables doivent être connus au moment de la compilation. Ceci permet au compilateur de détecter tout problème lié aux types des variables manipulées par l’application.
-
Langage fonctionnel : Kotlin est un langage purement fonctionnel. Il permet d’écrire des applications en utilisant seulement les principes de la programmation fonctionnelle.
-
« Null-safety » : les développeurs Java se confrontent souvent à des NullPointerException. Kotlin a été construit dans l’objectif d’éviter ce type...
Outils de développement
1. Environnement de développement intégré
Afin de commencer à développer en Kotlin, il est conseillé d’installer et de configurer un environnement de développement intégré (EDI). Comme pour tout autre langage de programmation, ce type d’environnement n’est pas obligatoire mais il est fortement recommandé pour faciliter et améliorer votre expérience de développement.
IntelliJ IDEA, l’EDI très connu dans le monde Java, supporte Kotlin par défaut sans que cela nécessite l’installation d’un plugin supplémentaire. Ceci est valable pour ses deux versions : Ultimate (payante) et Community Edition (gratuite).
La version d’IntelliJ IDEA appelée Android Studio, destinée aux développeurs Android, fournit exactement le même support du langage Kotlin.
L’EDI Eclipse nécessite quant à elle l’installation du plugin Kotlin Plugin For Eclipse. Cependant, ce plugin n’offre pas un support complet et à jour de toutes les fonctionnalités du langage. Il est recommandé d’utiliser IntelliJ IDEA ou Android Studio pour vos développements en Kotlin.
L’éditeur de texte très célèbre Visual Studio Code dispose aussi d’un plugin dédié pour Kotlin. Comme pour le plugin Eclipse, il n’offre qu’un support limité du langage.
2. Compilateur Kotlin
Des outils de production tels que Maven ou Gradle sont utilisés afin de gérer le build des applications Kotlin, comme c’est le cas en Java. Il n’est donc pas nécessaire d’installer et d’appeler directement le compilateur Kotlin.
Pour chaque version de Kotlin, il est cependant possible de télécharger le compilateur associé disponible dans le dépôt GitHub du projet Kotlin.
La configuration des outils Maven et Gradle permettant de supporter Kotlin sera traitée dans les deux sections suivantes.
3. Maven
Maven, créé en 2004, est un outil de production très utilisé dans le monde Java. Il permet de gérer tout le cycle de vie de la production : génération de code, compilation, test, génération de JAR/WAR, déploiement et publication de la documentation. La majorité des EDI fournissent un support complet de cet outil, soit directement comme pour IntelliJ IDEA, soit à travers un plugin comme pour Eclipse.
On peut ajouter Kotlin à un projet Maven en utilisant le plugin kotlin-maven-plugin. Ce plugin va gérer la compilation de tout code Kotlin dans les répertoires src/main/kotlin et src/test/kotlin. Le nom/emplacement des répertoires par défaut peut être modifié par simple configuration du plugin....
Les bases de Kotlin
1. Programme minimal
Comme la majorité des langages de programmation, tous les programmes Kotlin commencent à la fonction main. Un programme Kotlin minimale doit donc contenir cette fonction. Cette dernière doit accepter comme paramètre un tableau de chaînes de caractères. Ce tableau contiendra tous les arguments passés à l’application lors de son démarrage.
Contrairement à Java, la fonction main ne doit pas être enveloppée dans une classe statique. Ceci est un programme Kotlin valide :
fun main(args: Array<String>) {
println("Hello Kotlin!")
}
Une fois démarré, ce programme affichera la chaîne de caractères Hello Kotlin! puis il s’arrêtera puisqu’il s’agit de la dernière instruction spécifiée dans la fonction main.
Quand l’application Kotlin est compilée en bytecode Java, la fonction main est transformée en une fonction statique d’une classe générée automatiquement par le compilateur. Le nom de cette classe correspond au nom du fichier source Kotlin en plus d’un suffixe kt. Par exemple, si le fichier source porte le nom Main.kt, alors la classe statique générée par le compilateur aura le nom MainKt.
Il est également possible de définir la fonction main dans un objet (et non pas dans une classe) :
object MyApp {
@JvmStatic fun main(args: Array<String>) {
println("Hello Kotlin!")
}
}
Ce dernier programme aura exactement le même résultat que le précédent. La seule différence réside dans le fait que le nom de classe principale est celui de l’objet défini, en l’occurrence MyApp dans l’exemple.
Il faut noter qu’il n’est pas possible en Kotlin de définir la fonction main dans une classe comme en Java, du fait que Kotlin n’a pas de notion de « méthode statique ». L’annotation @JvmStatic permet de simuler ce comportement lorsque l’application écrite en Kotlin est compilée pour être exécutée par la plate-forme JVM.
On peut aussi noter qu’il n’y a pas besoin de points-virgules à la fin de chaque instruction. En Kotlin, le caractère « ; » est complètement optionnel et il n’est pas recommandé.
2. Les commentaires
Les commentaires ont la même syntaxe que Java et les autres langages dérivés du C. Les deux caractères « // » permettent de définir un commentaire sur une seule ligne, tandis que « /* */ » permet de définir un commentaire qui s’étend sur plusieurs lignes :
// This is a single line comment
/* This
is a multiline
comment
*/
3. Les variables
En Kotlin, il existe une distinction très claire entre deux catégories de variables :
-
Celles dont on peut modifier la valeur, on les déclare en utilisant le mot-clé var.
-
Celles dont on ne peut modifier la valeur une fois initialisée (variable immuable), on les déclare en utilisant le mot-clé val.
L’usage de ces deux mots-clés permet de rendre le code très lisible et de choisir plus judicieusement la catégorie de la variable lors de sa déclaration.
Pour toute variable, on doit définir en plus de la catégorie un nom et un type. Si la variable est immuable val, on doit aussi lui affecter une valeur (qu’on ne peut plus changer).
La syntaxe de déclaration de variables en Kotlin est la suivante :
val/var nomDeLaVariable : TypeDeLaVarialbe = valeurInitiale
Par exemple :
var counter : Int = 0
L’initialisation des variables modifiables est optionnelle. On peut déclarer une variable var sans valeur initiale :
var age : Int
En revanche, l’initialisation est obligatoire pour les variables immuables (val) :
val name : String = "Dupont"
Pour modifier la valeur d’une...
Les coroutines
1. Introduction
Aujourd’hui, les applications ont besoin d’exécuter plusieurs tâches simultanément. Elles doivent souvent gérer plusieurs requêtes et plusieurs utilisateurs concurrents. Ces applications doivent dès lors utiliser ce que l’on appelle un « thread ». Ce dernier est une unité d’exécution pouvant être planifiée et lancée indépendamment par le système d’exploitation. Une application peut créer et démarrer plusieurs threads à la fois. Cela rend possible l’exécution de plusieurs tâches simultanément par l’application.
Les threads sont gérés directement par le système d’exploitation, la machine virtuelle Java agit comme un intermédiaire entre l’application et le système d’exploitation. La JVM permet de masquer la complexité de la gestion des threads en fournissant un contrat simple et pratique à utiliser à travers les interfaces et classes du JDK. Les threads créés par une application ont un coût non négligeable qui peut impacter à la fois l’application et la machine hôte. En effet, pour chaque thread créé, le système d’exploitation alloue une zone mémoire dédiée où la JVM initialise une pile d’exécution pour stocker les variables locales et les métadonnées du thread. En plus, le système d’exploitation doit planifier et distribuer les ressources CPU entre tous les threads de toutes les applications lancées sur la machine hôte. Par conséquent, un nombre excessif de threads peut ralentir l’application. Il peut même monopoliser les ressources du système.
Kotlin propose une solution pour ce problème de coût des threads. Elle consiste à définir une unité d’exécution plus légère que les threads classiques. Cette unité ne nécessite pas de ressources mémoire et CPU dédiées. Plusieurs de ces unités peuvent partager le même thread système classique et ainsi partager les ressources entre elles. Ce type d’unité léger est appelée « coroutine ». Les threads virtuels introduits en Java 21 permettent aussi de répondre au même besoin.
Les coroutines sont gérées directement par Kotlin. La librairie des coroutines se charge de créer les threads, de les gérer et de distribuer l’exécution des différentes coroutines aux différents threads système. L’application peut alors créer des coroutines d’une façon illimitée pour lancer des tâches en parallèle sans avoir besoin de gérer la complexité et le coût de création et de gestion des threads.
2. Fonctionnement des coroutines
a. L’installation
La librairie standard de Kotlin n’intègre pas les coroutines. L’application doit l’ajouter explicitement en utilisant la librairie kotlinx.coroutines.
-
Gradle
implementation("org.jetbrains.kotlinx:kotlinx-
coroutines-core:1.8.0")
-
Maven
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core</artifactId>
<version>1.8.0</version>
</dependency>
Il faut noter que la librairie kotlinx.coroutines est versionnée indépendamment du langage Kotlin.
b. Les fonctions suspendues
Les coroutines reposent sur un type de fonction Kotlin appelé « fonctions suspendues ». Ces fonctions peuvent être interrompues puis reprises ultérieurement. Par exemple, prenons le cas d’une fonction suspendue qui requête une base de données puis transforme le résultat de la requête. Kotlin met en pause l’exécution de la fonction en attendant la réponse de la base de données. Une fois la réponse reçue, l’exécution de la fonction reprend pour exécuter...
Tester son code
1. Introduction
En tant que langage de la JVM, Kotlin est compatible avec toutes les librairies Java existantes. La librairie JUnit est la référence pour l’écriture des tests dans l’écosystème du langage Java. Elle peut aussi être utilisée pour écrire des tests en Kotlin. Cependant, toutes les capacités offertes par le langage Kotlin ne pourraient pas être pleinement exploitées en utilisant JUnit.
Kotest est une librairie de test alternative à JUnit. Elle est écrite entièrement en Kotlin. Elle permet d’écrire les tests d’une façon déclarative en se basant sur la puissance du langage Kotlin.
Kotest ne fournit pas de moteur d’exécution des tests. Elle se base sur le moteur de JUnit quand l’application cible la JVM.
a. Installation de Kotest avec Gradle
Puisque Kotest utilise le moteur de JUnit pour l’exécution des tests, il est nécessaire de configurer la tâche test de Gradle afin d’utiliser la plate-forme JUnit :
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
Le framework Kotest doit à son tour être ajouté aux dépendances du projet :
testImplementation("io.kotest:kotest-runner-junit5:5.8.0")
Il est d’usage d’utiliser ce framework avec la librairie d’assertion de Kotest. Cette librairie contient plusieurs méthodes utilitaires pour valider les valeurs renvoyées par le code durant les tests. Cette librairie peut être rajoutée en tant que dépendance comme suit :
testImplementation("io.kotest:kotest-assertions-core:5.8.0")
b. Installation de Kotest avec Maven
Comme pour les autres frameworks de tests, l’exécution des tests avec Maven est orchestrée par le plugin maven-surefire-plugin. Il est nécessaire de l’ajouter à la liste des plugins utilisés par le projet :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
Ensuite, il faut ajouter la dépendance vers Kotest avec un scope test :
<dependency>
<groupId>io.kotest</groupId>
<artifactId>kotest-runner-junit5-jvm</artifactId>
<version>5.8.0</version>
<scope>test</scope>
</dependency>
Optionnellement, il est possible d’ajouter la librairie d’assertions du framework Kotest :
<dependency>
<groupId>io.kotest</groupId>
<artifactId>kotest-assertions-core-jvm</artifactId>
<version>5.8.0</version>
<scope>test</scope>
</dependency>
c. Configuration d’IntelliJ
Pour pouvoir lancer les tests directement depuis l’environnement de développement IntelliJ, il est nécessaire d’installer le plugin Kotest. Ce dernier est disponible depuis la « Marketplace » des plugins d’IntelliJ :
Après l’installation du plugin, le redémarrage de l’EDI est nécessaire.
2. Écrire des tests avec Kotest
Le framework Kotest permet d’écrire les tests unitaires en suivant plusieurs styles différents. Cependant, pour faciliter la lecture du code, il est recommandé de suivre un seul style d’écriture pour tous les tests de la même application. La majorité des styles sont inspirés par les frameworks de tests des autres langages comme JUnit pour Java, ScalaTest pour le langage Scala et Karma pour le langage JavaScript. Offrir ces différents styles avait pour but de faciliter l’adoption de Kotlin et de Kotest par les développeurs accoutumés à d’autres langages. Le framework Kotest propose aussi ses propres styles qui ont pour but de faciliter l’écriture et la lecture des tests.
a. FunSpec
En suivant le style...
Conclusion
Dans ce chapitre, nous avons exploré le langage Kotlin et ses fonctionnalités de base. Kotlin propose une syntaxe qui se veut être plus simple. Il s’agit aussi d’une syntaxe qui impose une meilleure rigueur dans l’écriture du code. Devoir déclarer explicitement qu’une valeur peut être nullable ou qu’une classe peut être immuable permet par exemple au développeur de prendre conscience des besoins réels de ces variables et classes et de mieux gérer ses scénarios.
Les deux prochains chapitres se concentreront sur Ktor et Exposed, deux bibliothèques qui permettent de bénéficier pleinement de toutes les particularités du langage Kotlin. Ktor, à titre d’exemple, a su tirer avantage des coroutines pour offrir une gestion plus efficace et plus performante des requêtes HTTP. Quant à Exposed, elle simplifie la gestion des requêtes SQL et la connexion aux bases de données relationnelles.