Throw/Throws — ce que c'est, les opérateurs de lancement d'exceptions et leur fonctionnement dans le développement mobile

Auteur : IT Sectr Publié le : 2026-05-26 Temps de lecture : 9 min

Throw et Throws sont des mécanismes de lancement et de déclaration d'exceptions dans les langages de programmation. L'opérateur throw interrompt l'exécution normale d'une fonction et transmet l'objet d'erreur vers le haut de la pile d'appels. Le mot-clé throws dans la signature d'une fonction avertit la partie appelante de la possibilité d'une erreur, rendant le code prévisible. Selon la Documentation Kotlin (2026), throw en Kotlin est une expression, pas une instruction, ce qui permet de l'utiliser dans les blocs when et l'opérateur Elvis.

Points clés

  • Throw — un opérateur qui interrompt l'exécution de la fonction et transmet l'objet d'erreur vers le haut de la pile d'appels
  • Throws — un mot-clé dans la signature de la fonction qui déclare que la fonction peut lancer une exception
  • En Swift la fonction est marquée avec throws, l'appel nécessite try/try?/try!, et throw accepte tout type implémentant le protocole Error
  • En Kotlin throw est une expression de type Nothing, throws est absent (toutes les exceptions sont unchecked)
  • Les erreurs personnalisées sont créées via enum (Swift) ou sealed class (Kotlin) pour un traitement pratique dans catch

Qu'est-ce que Throw et Throws?

Throw est un opérateur qui génère une exception au point d'exécution du programme. Lorsque throw est rencontré, le flux d'exécution actuel est immédiatement interrompu et le contrôle est transféré au gestionnaire catch le plus proche dans la pile d'appels. Si aucun gestionnaire n'est trouvé, l'application plante. Throw dans le développement mobile est utilisé pour signaler des erreurs qui ne peuvent pas être traitées au niveau d'abstraction actuel — par exemple, une réponse serveur invalide, une absence de réseau ou des arguments incorrects.

Throws — un modificateur dans la signature d'une fonction (principalement en Swift) qui déclare que la fonction peut lancer une erreur. Cela fait partie du mécanisme des erreurs checked en Swift : la partie appelante est obligée de traiter l'erreur via do-catch, try?, try! ou de marquer sa propre fonction comme throws pour une propagation ultérieure. En Kotlin et Java, throws existe également, mais Kotlin le considère redondant — toutes les exceptions en Kotlin sont unchecked, ce qui signifie qu'elles peuvent ne pas être traitées sans contrainte syntaxique. Selon la Documentation Apple Swift (2026), throws en Swift est la seule façon de déclarer explicitement la possibilité d'une erreur dans le type de fonction, rendant les contrats d'API transparents pour le développeur.

La différence entre throw et throws est fondamentale : throw est une action (lancer une exception à l'exécution), throws est une déclaration (contrat à la compilation). Une fonction sans throws ne peut pas utiliser throw — le compilateur Swift produira une erreur. Une fonction avec throws peut ne pas utiliser throw — c'est permis mais sans signification. Cette séparation fait de throw/throws un outil puissant de conception d'API, où le contrat d'erreur est visible dans la signature de la fonction avant son appel.

Throw en Swift

En Swift, l'opérateur throw accepte tout type implémentant le protocole Error. Le plus souvent, il s'agit d'un enum avec des cas pour différents types d'erreurs. Swift ne prend pas en charge les exceptions checked à la Java — à la place, le type de fonction est marqué avec throws et le traitement est délégué à la partie appelante. Cela rend throw en Swift plus flexible mais aussi plus de responsabilité pour le développeur.

Protocole Error et types d'erreur

Tout type conforme au protocole Error peut être lancé via throw. Les développeurs utilisent le plus souvent un enum avec des cas sans valeurs associées (pour les erreurs simples) ou avec des valeurs associées (pour passer du contexte). Swift n'exige pas que l'erreur soit un enum — vous pouvez utiliser une struct ou une classe implémentant Error, mais l'enum est préférable grâce au exhaustive switch du côté du gestionnaire. Le compilateur vérifie que tous les cas sont traités dans do-catch.

swift
enum AuthError: Error {
    case invalidCredentials
    case tokenExpired
    case accountLocked(remainingMinutes: Int)
}

func login(username: String, password: String) throws -> Session {
    guard isValid(username) else {
        throw AuthError.invalidCredentials
    }
    let response = try api.authenticate(username, password)
    if response.isLocked {
        throw AuthError.accountLocked(
            remainingMinutes: response.lockDuration
        )
    }
    return Session(token: response.token)
}

AuthError définit trois scénarios : identifiants invalides, token expiré et compte verrouillé avec une valeur associée remainingMinutes. La fonction login est déclarée comme throws — le compilateur exige de l'appeler via try. Dans la fonction, throw est utilisé à deux endroits : pour un nom d'utilisateur invalide et pour un compte verrouillé. La valeur associée accountLocked permet de transmettre des données concrètes à l'utilisateur — combien de minutes attendre avant le déverrouillage. Cette approche élimine le besoin de points de terminaison API séparés pour vérifier l'état du verrouillage.

Throw en Kotlin

En Kotlin, throw est une expression de type Nothing, pas une instruction. Cela signifie que throw peut être utilisé du côté droit d'une affectation, dans des expressions when et l'opérateur Elvis ?:. Le type Nothing est un sous-type spécial de tous les types en Kotlin, ce qui permet d'utiliser throw dans des endroits où une valeur de n'importe quel type est requise. Le compilateur comprend que l'exécution ne continue pas après throw et ne nécessite pas de branche pour ce cas.

Type Nothing et son rôle dans la composition

Nothing est un type unique en Kotlin qui est un sous-type de tous les types possibles. Une fonction qui retourne Nothing (par exemple, TODO()) ne se termine jamais normalement — soit elle lance toujours une exception, soit elle entre dans une boucle infinie. Cela fait de throw un candidat naturel pour une utilisation dans des endroits où une valeur est requise : opérateur Elvis, when sans else, initialisation de variable. Si throw se trouve dans une branche when, le compilateur comprend que la branche mène à Nothing et ne nécessite pas de return ou else pour cette branche.

kotlin
data class Config(val apiUrl: String, val timeoutSec: Int)

class ConfigParser {
    fun parse(json: String): Config {
        val obj = JSONObject(json)
        val url = obj.optString("apiUrl")
            ?: throw IllegalArgumentException("apiUrl is required")
        val timeout = obj.optInt("timeoutSec", 30)
        return Config(url, timeout)
    }

    fun getErrorMessage(code: Int): String {
        return when (code) {
            404 -> "Not found"
            500 -> "Server error"
            else -> throw IllegalArgumentException("Unknown code: $code")
        }
    }
}

Dans le premier exemple, throw est utilisé dans l'opérateur Elvis ?: : si le champ apiUrl est absent du JSON, l'expression throw interrompt immédiatement l'exécution et lance une IllegalArgumentException. Le type Nothing permet au compilateur de déduire le type du côté droit comme String (Elvis attend String, throw a le type Nothing, Nothing est un sous-type de String). Dans le deuxième exemple, throw dans une expression when : si le code ne correspond à aucun connu, une exception est lancée. Le compilateur comprend que le code après throw est inaccessible, donc le type de retour de la fonction String n'est pas violé.

Throws dans la signature de fonction et rethrows

En Swift, throws est spécifié après la liste des paramètres et avant la flèche du type de retour. Une fonction avec throws ne peut appeler que d'autres fonctions throws à l'intérieur de do-catch ou avec try?. Si une fonction throws ne traite pas l'erreur, elle la transmet à la partie appelante. Swift prend également en charge rethrows — un modificateur pour les fonctions d'ordre supérieur qui acceptent une closure throws et propagent son erreur. rethrows signifie que la fonction ne lance une erreur que si la closure passée en a lancé une — la fonction elle-même ne génère pas d'erreur.

swift
func mapValues<T>(
    _ array: [T],
    transform: (T) throws -> U
) rethrows -> [U] {
    var result = [U]()
    for element in array {
        result.append(try transform(element))
    }
    return result
}

// Utilisation avec une closure throws
let parsed = try mapValues(jsonStrings) { str in
    let data = Data(str.utf8)
    return try JSONDecoder().decode(Item.self, from: data)
}

rethrows permet à la fonction mapValues d'être flexible : elle accepte à la fois les closures throws et normales. Si une closure throws est passée, l'appel à mapValues nécessite try ; si normale, try n'est pas nécessaire. Cela fait de rethrows un outil idéal pour les fonctions d'ordre supérieur telles que map, filter, reduce dans la bibliothèque standard de Swift. Recommandation Apple : utilisez rethrows pour les API qui acceptent des closures throws et dont la seule source d'erreur est cette closure. Si la fonction peut lancer sa propre erreur, utilisez throws.

Exceptions checked vs unchecked

Swift throws est plus proche des exceptions checked (comme en Java) — les erreurs lancées sont déclarées dans la signature. Kotlin et Dart utilisent des exceptions unchecked — throws dans la signature n'est pas nécessaire. La différence est fondamentale : checked oblige le développeur à traiter l'erreur (plus sûr mais plus verbeux), unchecked donne de la liberté mais augmente le risque d'oublier de traiter une erreur. Swift a choisi checked pour throws, Kotlin a choisi unchecked pour toutes les exceptions. Les deux approches ont des avantages : Swift est plus fiable au niveau du langage, Kotlin est plus compact et pratique dans les chaînes de transformations fonctionnelles.

Types d'erreur personnalisés

Pour un traitement structuré des erreurs dans les applications mobiles, il est recommandé de créer des types d'erreur personnalisés au lieu d'utiliser Exception ou Error de base. En Swift, on utilise un enum avec le protocole Error ; en Kotlin, une sealed class héritant de Throwable (ou de Exception) ; en Dart, une classe héritant de Exception. Les types personnalisés permettent de regrouper les erreurs par catégories et de passer des données associées.

LangageType d'erreurCaractéristique
Swiftenum: Error { ... }Valeurs associées, exhaustive switch dans catch
Kotlinsealed class : Throwable()Data class pour les erreurs avec champs, expression when
Dartclass implements ExceptionChamp Message, clause on dans catch
Javaclass extends ExceptionChecked vs unchecked, throws obligatoire dans la signature

Lors de la conception d'erreurs personnalisées, suivez la règle : une erreur — un scénario. Ne combinez pas différentes causes dans un seul type avec un indicateur String message — créez des cas/sous-classes séparés pour chaque scénario. Cela permettra à la partie appelante de traiter chaque cas via le pattern matching (when/switch) plutôt que par comparaison de chaînes. En Swift, cela fournit un exhaustive checking — le compilateur avertira si un cas de l'enum NetworkError n'est pas traité.

Exemple d'erreur personnalisée en Kotlin

kotlin
sealed class NetworkError(val message: String) : Throwable(message) {
    data class Timeout(val durationMs: Long) :
        NetworkError("Request timed out after ${durationMs}ms")
    data class HttpError(val code: Int, val body: String?) :
        NetworkError("HTTP $code")
    data class NoConnection(val cause: IOException) :
        NetworkError("No internet connection")
}

La sealed class NetworkError hérite de Throwable (le type d'exception standard en Kotlin). Chaque sous-classe est une data class avec ses propres champs : Timeout contient la durée du délai d'attente en millisecondes, HttpError contient le code et le corps de la réponse, NoConnection contient l'IOException d'origine. Cette conception permet de traiter chaque erreur via when avec correspondance exhaustive (lorsque vous ajoutez une nouvelle sous-classe, le compilateur force la mise à jour de toutes les expressions when).

Try, try? et try! en Swift

Swift propose trois façons d'appeler des fonctions throws, chacune avec son propre contrat de sécurité. try est la méthode standard : nécessite do-catch ou d'être à l'intérieur d'une fonction throws. try? convertit l'erreur en nil — le résultat devient optionnel, en cas d'erreur il retourne nil, le type passe de T à T?. try! — exécution forcée sans traitement : si une erreur est lancée, l'application plante. Utilisez try! seulement lorsque vous êtes absolument certain qu'une erreur est impossible (par exemple, des données manifestement valides).

swift
let configPath = Bundle.main.path(forResource: "config", ofType: "json")!

// try? — résultat optionnel
let data = try? Data(contentsOf: URL(fileURLWithPath: configPath))
let json = try? JSONSerialization.jsonObject(with: data ?? Data())

// try! — succès garanti (seulement quand on est sûr)
let decoder = JSONDecoder()
let defaultConfig = try! decoder.decode(
    Config.self,
    from: Config.defaultJSON
)

// try — traitement standard
do {
    let user = try fetchUser()
    showUser(user)
} catch let error as NetworkError {
    showRetryAlert(error.message)
}

Dans l'exemple, try! est utilisé pour du JSON manifestement valide intégré dans le bundle de l'application — une erreur de décodage est impossible avec une version correcte. try? est utilisé pour lire un fichier de configuration — si le fichier est manquant ou corrompu, l'application utilise des valeurs par défaut plutôt que de planter. try dans do-catch est utilisé pour les requêtes réseau où une erreur est attendue et nécessite une réponse de l'utilisateur. Recommandation : évitez try! dans le code de production — utilisez-le uniquement pour les données constantes vérifiées au moment de la construction.

Questions fréquentes

Quelle est la différence entre throw et throws en Swift?

Throw est un opérateur qui lance une erreur pendant l'exécution du programme, interrompant le flux. Throws est un modificateur de signature de fonction qui déclare que la fonction peut lancer une erreur. Une fonction sans throws ne peut pas utiliser throw. Throws est un contrat à la compilation, throw est une action à l'exécution.

Pourquoi n'y a-t-il pas de throws en Kotlin?

Kotlin suit la philosophie des exceptions unchecked : toutes les exceptions peuvent rester non traitées sans contrainte syntaxique. Les développeurs de Kotlin estiment que throws en Java conduit à des blocs try-catch excessifs et à l'ignorance des exceptions checked via des catch vides. Le type Nothing de Kotlin permet d'utiliser throw comme expression, remplaçant throws par une approche plus flexible.

Quand utiliser try! en Swift?

try! n'est acceptable que lorsque vous êtes absolument certain qu'une erreur est impossible : JSON manifestement valide du bundle, données constantes, schémas d'URL corrects. Dans le code de production, try! est une exception, pas une règle. try? est préférable pour les scénarios optionnels avec une valeur de repli, try avec do-catch pour le traitement obligatoire des erreurs.

Qu'est-ce que rethrows en Swift?

Rethrows est un modificateur pour les fonctions qui acceptent des closures throws. Une fonction avec rethrows ne lance une erreur que si la closure passée en a lancé une. Cela permet aux fonctions d'ordre supérieur (map, filter) de fonctionner avec des closures throws et non-throws sans forcer try du côté appelant.

Peut-on lancer une erreur dans un bloc catch?

Oui, dans catch vous pouvez utiliser throw pour propager l'erreur vers le haut de la pile, en l'enveloppant dans un type différent ou en ajoutant du contexte. Cela s'appelle le chaînage d'erreurs ou rethrow. En Swift, un autre throw dans catch suffit ; en Kotlin, throw dans un bloc catch. Le bloc finally s'exécute avant que le contrôle ne soit transmis plus haut.

Résumé

  • Throw — un opérateur de lancement d'exception qui interrompt le flux actuel et transmet l'objet d'erreur vers le haut de la pile
  • Throws — une déclaration à la compilation dans la signature de la fonction sur la possibilité d'une erreur, obligatoire en Swift, absent en Kotlin
  • En Swift throw accepte enum: Error, la fonction est marquée avec throws, appelée via try / try? / try!
  • En Kotlin throw est une expression de type Nothing, permettant son utilisation dans when, l'opérateur Elvis et les affectations
  • Rethrows en Swift permet aux fonctions d'ordre supérieur de propager les erreurs uniquement depuis les closures passées
  • Les erreurs personnalisées sont créées via enum (Swift) ou sealed class (Kotlin) avec des valeurs associées pour des informations détaillées
  • Concevez les types d'erreur selon le principe "un cas — un scénario" pour un traitement pratique via le pattern matching

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi