Cours Kotlin Complet 🟣
Les 12 chapitres essentiels — null safety, data classes, coroutines et l'écosystème Android/multiplateforme
🏠 Hub Programmation
🐍 Python
⚡ JavaScript
☕ Java
☁️ AWS Cloud Practitioner
Introduction et premier programme
Kotlin = Java en mieux. Créé par JetBrains, adopté par Google comme langage officiel pour Android en 2019. Il est 100% interopérable avec Java — vous pouvez appeler du Java depuis Kotlin et vice versa. Mais Kotlin est plus concis, plus sûr (null safety), et plus expressif.
# – IntelliJ IDEA (recommandé) ou Android Studio
# – ou via sdkman : sdk install kotlin
# Compiler et exécuter
kotlinc hello.kt -include-runtime -d hello.jar
java -jar hello.jar
# REPL interactif
kotlinc
# Avec Gradle (standard)
# build.gradle.kts
# plugins
gradle run
| Caractéristique | Kotlin |
|---|---|
| Typage | Statique et fort avec inférence |
| Paradigme | POO + fonctionnel |
| Compilation | JVM, JS, Native (LLVM), WASM |
| Null Safety | Intégré dans le système de types |
| Interop | 100% compatible Java |
| Usage | Android (officiel), backend (Ktor, Spring), multiplateforme |
| Convention | camelCase (fonctions/variables), PascalCase (classes) |
Variables et types de données
val nom = « Alice » // Type inféré : String
val pi = 3.14159 // Double
val age: Int = 25 // Type explicite
// var = mutable
var score = 0
score += 10 // ✅
// nom = « Bob » ❌ Val cannot be reassigned
| Type | Taille | Exemple |
|---|---|---|
| Int | 32 ou 64 bits | 42 |
| Long | 64 bits | 42L |
| Double | 64 bits | 3.14 |
| Float | 32 bits | 3.14f |
| Boolean | 1 bit | true / false |
| Char | 16 bits | 'A' |
| String | variable | « Hello $name » |
En Kotlin, tout est objet. Pas de types primitifs — Int, Boolean, etc. sont des classes. Le compilateur optimise en primitifs JVM quand possible. Pas besoin de int vs Integer comme en Java.
// String templates
val msg = « Nom: $nom, Age: $ »
// Multi-ligne
val texte = « » »
|Ligne 1
|Ligne 2
« » ».trimMargin()
// Méthodes
s.length // 11
s.isEmpty() // false
s.uppercase() // « HELLO WORLD »
s.lowercase() // « hello world »
s.contains(« World ») // true
s.startsWith(« He ») // true
s.endsWith(« ld ») // true
s.replace(« World », « Kotlin ») // « Hello Kotlin »
s.split( » « ) // [« Hello », « World »]
s.trim()
s.substring(0, 5) // « Hello »
s.toIntOrNull() // null (safe conversion)
// Conversion
« 42 ».toInt() // 42 (throws si invalide)
« 42 ».toIntOrNull() // 42 ou null (safe)
42.toString() // « 42 »
Fonctions
fun add(a: Int, b: Int): Int
// Single-expression (= au lieu de )
fun add(a: Int, b: Int) = a + b
// Paramètres par défaut
fun greet(name: String, greeting: String = « Bonjour ») =
« $greeting $name ! »
greet(« Alice ») // « Bonjour Alice ! »
greet(« Alice », « Salut ») // « Salut Alice ! »
// Named arguments
greet(greeting = « Hey », name = « Bob »)
// Varargs
fun sum(vararg nums: Int): Int = nums.sum()
sum(1, 2, 3) // 6
// Unit = void (type de retour par défaut)
fun log(msg: String): Unit
fun log(msg: String) // Unit implicite
Les paramètres par défaut remplacent la surcharge de méthodes. En Java, il faut écrire 3 constructeurs pour 3 combinaisons de paramètres. En Kotlin, une seule fonction avec des défauts suffit.
fun String.addExclamation() = « $this! »
« Hello ».addExclamation() // « Hello! »
fun Int.isEven() = this % 2 == 0
4.isEven() // true
fun <T> List<T>.secondOrNull(): T? = getOrNull(1)
Les extension functions sont l'une des fonctionnalités les plus puissantes de Kotlin. Elles permettent d'enrichir des classes existantes (même de la librairie standard) sans héritage ni modification.
Structures de contrôle
val label = if (age >= 18) « majeur » else « mineur »
// when — le switch surpuissant de Kotlin (expression aussi)
val label = when (age)
// when sans argument (remplace if/else if)
val label = when
// when avec type check (smart cast)
fun describe(x: Any): String = when (x)
// for
for (i in 0..4) // 0, 1, 2, 3, 4 (inclusif)
for (i in 0 until 5) // 0, 1, 2, 3, 4 (exclusif)
for (i in 10 downTo 0 step 2) // 10, 8, 6, 4, 2, 0
for (item in list)
for ((i, v) in list.withIndex())
for ((key, value) in map)
POO : Classes et objets
class Person(val name: String, var age: Int)
val alice = Person(« Alice », 25) // Pas de « new » !
alice.name // « Alice »
alice.age = 26
val/var dans le constructeur = déclare + initialise les propriétés en une seule ligne. En Java, il faudrait les champs, le constructeur, les getters et les setters — facilement 20 lignes. En Kotlin : 1 ligne.
// equals(), hashCode(), toString(), copy(), componentN()
data class User(val name: String, val email: String, val age: Int)
val alice = User(« Alice », « alice@mail.com », 25)
println(alice) // User(name=Alice, email=alice@mail.com, age=25)
// copy — copie avec modification
val bob = alice.copy(name = « Bob », email = « bob@mail.com »)
// Destructuring
val (name, email, age) = alice
// Comparaison structurelle (pas de référence)
val alice2 = User(« Alice », « alice@mail.com », 25)
alice == alice2 // true ✅ (comparaison par valeur)
En Java, la même data class nécessiterait ~60 lignes (champs, constructeur, getters, equals, hashCode, toString). En Kotlin : 1 ligne. C'est le type le plus utilisé pour transporter des données.
Héritage et interfaces
open class Animal(val name: String)
class Dog(name: String) : Animal(name)
class Cat(name: String) : Animal(name)
interface Clickable
// Implémentation multiple
class Button : Drawable, Clickable
// Abstract class
abstract class Shape
Null Safety
var name: String = « Alice »
name = null // ❌ Erreur de compilation !
// String? = nullable (peut être null)
var name: String? = « Alice »
name = null // ✅ OK
// ⚠️ On ne peut PAS appeler des méthodes directement sur un nullable
name.length // ❌ Erreur — name est peut-être null
// Safe call (?.) — retourne null si null
name?.length // Int? (null si name est null)
// Elvis operator (??) — valeur par défaut
val len = name?.length ?: 0
// Safe call chaîné
val city = user?.address?.city ?: « Inconnue »
// let — exécuter un bloc si non-null
name?.let
// Smart cast — le compilateur sait que ce n'est plus null
if (name != null)
// !! — force non-null (DANGEREUX — NullPointerException si null)
name!!.length // ⚠️ Crash si null !
Le null safety de Kotlin élimine les NullPointerException à la compilation. C'est le problème n°1 en Java (appelé le « billion dollar mistake »). En Kotlin, le compilateur force la gestion de null avant d'utiliser une valeur.
Collections et fonctions
val nums: List<Int> = listOf(1, 2, 3)
val tags: Set<String> = setOf(« a », « b », « a ») //
val ages: Map<String, Int> = mapOf(« Alice » to 25, « Bob » to 30)
// MUTABLES
val nums = mutableListOf(1, 2, 3)
nums.add(4)
nums.removeAt(0)
nums += 5
val ages = mutableMapOf(« Alice » to 25)
ages[« Bob »] = 30
ages.getOrDefault(« Eve », 0) // 0
// Propriétés communes
nums.size // 4
nums.isEmpty() // false
nums.contains(3) // true
3 in nums // true (operator)
nums.first() // 2
nums.last() // 5
Immuable par défaut. listOf, setOf, mapOf créent des collections en lecture seule. Utilisez les versions mutable uniquement quand vous devez modifier la collection. C'est plus sûr pour la concurrence.
// Lambda syntax :
val double =
// it = paramètre implicite (un seul param)
val double =
// Chaîner
val result = nums
.filter // [2, 4, 6, 8, 10]
.map // [6, 12, 18, 24, 30]
.take(3) // [6, 12, 18]
// Autres méthodes essentielles
nums.map // Transformer
nums.filter // Filtrer
nums.reduce // Réduire (55)
nums.fold(0) // Réduire avec valeur initiale
nums.sum() // 55
nums.average() // 5.5
nums.min() // 1
nums.max() // 10
nums.count // 5
nums.any // true
nums.all // true
nums.none // true
nums.sortedDescending() // [10, 9, …, 1]
nums.distinct() // Dédupliquer
nums.groupBy //
nums.flatMap // [1,2, 2,4, 3,6, …]
nums.associate //
nums.joinToString(« , « ) // « 1, 2, 3, … »
// Sequence (lazy — pour les grandes collections)
nums.asSequence()
.filter
.map
.take(3)
.toList()
Classes avancées
enum class Color(val hex: String)
// Sealed class — enum sur stéroïdes (variantes avec données)
sealed class Result
// when exhaustif sur sealed (pas besoin de else)
fun handle(result: Result) = when (result)
// object — singleton
object Database
Database.connect()
// companion object — méthodes « statiques »
class User(val name: String)
val u = User.create(« Alice »)
Generics
fun <T> firstOrNull(list: List<T>): T? = list.firstOrNull()
// Avec contrainte
fun <T : Comparable<T>> max(a: T, b: T): T = if (a > b) a else b
// Classe générique
class Stack<T>
val stack = Stack<Int>()
stack.push(42)
// Variance
// out T = covariant (producteur — List
// in T = contravariant (consommateur — Comparable
fun printAll(items: List<out Any>)
// Reified type (inline function — accès au type T au runtime)
inline fun <reified T> isType(value: Any): Boolean = value is T
Coroutines
import kotlinx.coroutines.*
// suspend = fonction qui peut être suspendue (non-bloquante)
suspend fun fetchUser(id: Int): User
// launch — fire-and-forget (Job)
fun main() = runBlocking
// async — retourne un résultat (Deferred)
fun main() = runBlocking
// withContext — changer de dispatcher
suspend fun heavyComputation(): Int = withContext(Dispatchers.Default)
Les coroutines Kotlin sont comme les goroutines Go ou async/await JavaScript — mais intégrées dans le langage. Elles sont ultra-légères (pas de thread par coroutine) et annulables via les scopes structurés.
Dispatchers.Main // Thread principal (Android UI)
Dispatchers.IO // I/O (réseau, fichiers)
Dispatchers.Default // CPU-intensive
// Structured concurrency — le scope gère le cycle de vie
suspend fun loadDashboard() = coroutineScope
// Flow — stream asynchrone (comme Observable/RxJava)
fun countDown(): Flow<Int> = flow
countDown()
.filter
.collect
Kotlin idiomatique
// let — transformer un résultat, chaîner sur nullable
val len = name?.let
// apply — configurer un objet (retourne l'objet)
val user = User().apply
// also — side effect (retourne l'objet)
val nums = mutableListOf(1, 2, 3)
.also
// run — exécuter un bloc et retourner le résultat
val result = user.run
// with — comme run mais pas en extension
val info = with(user)
| Fonction | Réf objet | Retourne | Usage typique |
|---|---|---|---|
| let | it | Lambda result | Nullable check, transformer |
| run | this | Lambda result | Initialiser + calculer |
| with | this | Lambda result | Appeler plusieurs méthodes |
| apply | this | Object | Configurer un objet |
| also | it | Object | Side effects (logging) |
val heavyData: List<String> by lazy
// Destructuring
val (name, age) = Person(« Alice », 25)
for ((key, value) in map)
// Type aliases
typealias UserMap = Map<String, List<User>>
// Operator overloading
data class Point(val x: Double, val y: Double)
Point(1.0, 2.0) + Point(3.0, 4.0) // Point(4.0, 6.0)
// Kotlin DSL (type-safe builders)
val html = buildString
✅ À FAIRE
• val par défaut (immutabilité)
• data class pour les DTO
• sealed class pour les états
• ?. et ?: pour le null safety
• when au lieu de if/else if
• Extension functions
• Coroutines pour l'async
• listOf par défaut (immuable)
• Named arguments pour la lisibilité
❌ À ÉVITER
• !! (force non-null) en production
• var quand val suffit
• mutableListOf quand listOf suffit
• Java-style getters/setters
• lateinit abusif
• Scope functions imbriquées
• Ignorer les warnings
• Any au lieu de generics
• Callbacks au lieu de coroutines
if (x is String), x est utilisable comme String.🏠 Hub Programmation
🐍 Cours Python
⚡ Cours JavaScript
☕ Cours Java
☁️ AWS Cloud Practitioner
Cours Kotlin Complet — Null Safety, Coroutines et écosystème Android
Référence : kotlinlang.org | Android Kotlin
