Bases
Hello World
fun main() { println("Hello, World!") }
Variables
val name = "Kotlin" // immuable (à préférer) var count = 0 // mutable val pi: Double = 3.14159 // type explicite const val MAX = 100 // constante à la compilation
Types de base
Int, LongEntiers signés 32 bits / 64 bits
Double, FloatVirgule flottante 64 bits / 32 bits
Booleantrue / false
CharCaractère Unicode unique
StringTexte immuable, supporte les templates
UnitÉquivalent de void (valeur unique)
NothingLa fonction ne retourne jamais (ex. lève une exception)
Templates de chaînes
val name = "World" println("Hello, $name!") println("Length: ${name.length}") val raw = """line 1 |line 2""".trimMargin()
Fonctions
Déclaration de fonction
fun add(a: Int, b: Int): Int { return a + b } fun add(a: Int, b: Int) = a + b // expression unique
Arguments par défaut et nommés
fun greet(name: String, greeting: String = "Hello") { println("$greeting, $name!") } greet("Alice") // Hello, Alice! greet("Bob", greeting = "Hi") // Hi, Bob!
Fonctions d'ordre supérieur
fun operate(a: Int, b: Int, op: (Int, Int) -> Int): Int { return op(a, b) } val sum = operate(3, 4) { a, b -> a + b }
Varargs
fun sum(vararg nums: Int): Int = nums.sum() sum(1, 2, 3) val arr = intArrayOf(1, 2, 3) sum(*arr) // opérateur de décomposition
Classes
Définition de classe
class Person(val name: String, var age: Int) { fun greet() = "Hi, I'm $name" } val p = Person("Alice", 30) println(p.name)
Héritage
open class Shape(val sides: Int) { open fun area(): Double = 0.0 } class Circle(val r: Double) : Shape(0) { override fun area() = Math.PI * r * r }
Modificateurs de visibilité
publicVisible partout (par défaut)
privateVisible dans la classe / le fichier
protectedClasse et sous-classes
internalMême module uniquement
Classes abstraites et interfaces
interface Drawable { fun draw() } abstract class Widget : Drawable { abstract val label: String } class Button(override val label: String) : Widget() { override fun draw() = println("Drawing $label") }
Sécurité null
Types nullables
var name: String? = null // nullable val len = name?.length // appel sécurisé : null val len2 = name?.length ?: 0 // opérateur Elvis : 0 val len3 = name!!.length // assertion non-null (lève exception)
Opérations sécurisées
?.Appel sécurisé — retourne null si le récepteur est null
?:Elvis — valeur par défaut si null
!!Assertion non-null (lève une exception si null)
?.let { }Exécuter le bloc uniquement si non-null
as?Cast sécurisé — retourne null en cas d'échec
Casts intelligents
if (obj is String) println(obj.length) // cast automatique when (obj) { is Int -> println(obj + 1) is String -> println(obj.uppercase()) }
Collections
Créer des collections
val list = listOf(1, 2, 3) // immuable val mList = mutableListOf(1, 2, 3) // mutable val map = mapOf("a" to 1, "b" to 2) val set = setOf("x", "y", "z")
Opérations sur les collections
val nums = listOf(1, 2, 3, 4, 5) nums.filter { it > 2 } // [3, 4, 5] nums.map { it * 2 } // [2, 4, 6, 8, 10] nums.firstOrNull { it > 3 } // 4 nums.sumOf { it } // 15
Opérations courantes
.filter { }Garder les éléments correspondant au prédicat
.map { }Transformer chaque élément
.flatMap { }Mapper et aplatir
.groupBy { }Regrouper par clé dans une Map
.sortedBy { }Trier par sélecteur
.associate { }Transformer en Map (paires clé-valeur)
.any { } / .all { }Vérifier si quelqu'un/tous correspondent au prédicat
.fold(init) { }Réduire avec un accumulateur initial
Coroutines
Coroutine de base
import kotlinx.coroutines.* fun main() = runBlocking { launch { delay(1000); println("World") } println("Hello") }
Async / Await
val deferred = async { fetchData() } val result = deferred.await() // parallèle : lancer plusieurs async, attendre tous val (a, b) = awaitAll(async { fetchA() }, async { fetchB() })
Constructeurs de coroutines
launch { }Coroutine fire-and-forget (retourne Job)
async { }Retourne Deferred avec résultat
runBlocking { }Fait le pont entre code bloquant et suspendu
withContext(dispatcher)Changer le contexte de la coroutine
coroutineScope { }Portée de concurrence structurée
Dispatchers
Dispatchers.DefaultTravail intensif CPU (pool de threads)
Dispatchers.IOOpérations I/O bloquantes
Dispatchers.MainThread principal/UI (Android, Swing)
Dispatchers.UnconfinedDémarre dans le thread appelant, reprend n'importe où
Extensions
Fonctions d'extension
fun String.isPalindrome(): Boolean { return this == this.reversed() } println("racecar".isPalindrome()) // true
Propriétés d'extension
val String.wordCount: Int get() = this.split("\\s+".toRegex()).size println("hello world".wordCount) // 2
Surcharge d'opérateurs
data class Vec(val x: Double, val y: Double) { operator fun plus(other: Vec) = Vec(x + other.x, y + other.y) } val v = Vec(1.0, 2.0) + Vec(3.0, 4.0) // Vec(4.0, 6.0)
Data classes
Data class
data class User(val name: String, val age: Int) val u1 = User("Alice", 30) val u2 = u1.copy(age = 31) // copie non destructive val (name, age) = u1 // déstructuration
Membres auto-générés
equals()Égalité structurelle basée sur les propriétés
hashCode()Cohérent avec equals()
toString()User(name=Alice, age=30)
copy()Créer une copie modifiée
componentN()Support de la déstructuration
Classes enum
enum class Direction { NORTH, SOUTH, EAST, WEST } val dir = Direction.NORTH when (dir) { Direction.NORTH -> "up"; else -> "other" }
Classes sealed
Hiérarchie de classe sealed
sealed class Result { data class Success(val data: T) : Result() data class Error(val message: String) : Result() data object Loading : Result() }
When exhaustif
fun handle(result: Result): String = when (result) { is Result.Success -> result.data is Result.Error -> "Error: ${result.message}" is Result.Loading -> "Loading..." } // pas de else nécessaire — le compilateur vérifie l'exhaustivité
Sealed vs Enum
Sealed classLes sous-classes peuvent avoir des états différents
Sealed interfacePermet l'héritage multiple
Enum classEnsemble fixe d'instances singleton
data objectSingleton avec surcharge de toString()
Fonctions de portée
Comparaison des fonctions de portée
letContexte comme it, retourne le résultat du lambda
runContexte comme this, retourne le résultat du lambda
with(obj)Contexte comme this, retourne le résultat du lambda
applyContexte comme this, retourne l'objet contexte
alsoContexte comme it, retourne l'objet contexte
let et apply
val name: String? = "Alice" name?.let { println("Name is $it") } val person = Person("Bob", 25).apply { age = 26 // configurer l'objet }
run et with
val result = "Hello".run { uppercase() + " WORLD" } val info = with(person) { "$name is $age years old" }
also
val numbers = mutableListOf(1, 2, 3) .also { println("Original: $it") } .also { it.add(4) } // also est utile pour les effets de bord (journalisation, validation)