Try-Catch : essence, construction de capture d'exceptions et fonctionnement dans le développement mobile

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

Try-Catch est une construction de capture d'exceptions qui permet d'exécuter du code potentiellement dangereux dans un bloc protégé et de traiter correctement les erreurs sans arrêt brutal du programme. Le bloc try contient le code qui peut lever une exception, catch l'intercepte et exécute la logique de récupération. Selon la Apple Swift Documentation (2026), le bloc finally s'exécute qu'une exception ait été levée ou non, garantissant la libération des ressources.

Points clés

  • Try-Catch est une construction de capture d'exceptions qui empêche l'arrêt brutal du programme en cas d'erreurs
  • Le bloc try contient le code qui peut lever une exception — l'exécution s'arrête à la première erreur
  • Le bloc catch capture l'exception du type spécifié et exécute la logique de traitement ou de récupération
  • Le bloc finally s'exécute obligatoirement après try/catch pour libérer les ressources, par exemple fermer les fichiers
  • Les try-catch imbriqués permettent de traiter les erreurs à différents niveaux d'abstraction au sein d'une même fonction

Qu'est-ce que Try-Catch ?

Try-Catch est une construction fondamentale de gestion structurée des exceptions présente dans la plupart des langages de programmation modernes. Elle se compose de trois blocs : try (tentative d'exécution de code dangereux), catch (interception et traitement de l'exception) et finally optionnel (finalisation). L'idée de la construction est de séparer la logique métier de la logique de gestion des erreurs, rendant le code plus lisible et prévisible.

Le concept a été implémenté pour la première fois en C++ sous forme de try/catch, puis adopté par Java, C#, Swift, Kotlin, Dart, Python, JavaScript et d'autres langages. Chaque langage ajoute ses propres particularités : en Swift, le bloc catch doit être exhaustif, en Kotlin, try-catch peut être une expression, en Dart, finally est obligatoire pour les ressources de flux. Malgré les différences, le principe de base est le même : une erreur est traitée aussi près que possible de son lieu d'apparition, et non globalement.

L'utilisation de Try-Catch est particulièrement importante dans le développement mobile, où les facteurs externes — perte de réseau, réponse incorrecte du serveur, mémoire insuffisante — sont constants. Une gestion appropriée des exceptions empêche les crashs de l'application et garantit une UX correcte : l'utilisateur voit un message d'erreur au lieu d'une fermeture soudaine. Selon le Google Android Kotlin Style Guide (2026), toute fonction qui peut lever une exception doit soit la traiter via try-catch, soit déclarer throws dans sa signature.

Comment fonctionne Try-Catch

Le mécanisme d'exécution de try-catch repose sur le déroulement de la pile (stack unwinding). Lorsqu'une exception est levée à l'intérieur du bloc try via l'opérateur throw (ou à la suite d'une erreur système), le flux d'exécution normal est immédiatement interrompu. L'exécution remonte d'un niveau dans la pile d'appels à la recherche d'un bloc catch approprié. Les langages modernes recherchent un catch dont le type correspond au type de l'exception levée en utilisant un mécanisme de correspondance de types (type matching).

Si un catch correspondant est trouvé, son corps est exécuté, après quoi l'exécution se poursuit après l'ensemble de la construction try-catch-finally. Si aucun catch n'est trouvé, l'exception remonte dans la pile et peut être traitée à un niveau supérieur — jusqu'à un gestionnaire global qui, dans une application mobile, affiche une boîte de dialogue d'erreur. Si l'exception n'est traitée nulle part, l'application plante. C'est pourquoi le traitement correct de tous les types d'exceptions possibles est crucial pour la stabilité de l'application.

Syntaxe de la construction de base

kotlin
fun readUserData(): User {
    return try {
        val response = api.fetchUser()
        parseUser(response)
    } catch (e: IOException) {
        logError("Erreur réseau", e)
        throw AppException("Échec du chargement des données")
    } catch (e: JsonParseException) {
        logError("Erreur d'analyse", e)
        return User.default()
    } finally {
        closeLoadingIndicator()
    }
}

Le code tente d'abord d'effectuer une requête à l'API et d'analyser la réponse. Si une IOException (problème réseau) se produit, l'exception est journalisée et relancée comme AppException. Si une JsonParseException se produit — un utilisateur par défaut est renvoyé. Le bloc finally garantit de masquer l'indicateur de chargement, évitant les fuites de composants d'interface à l'écran.

Try-Catch dans Swift

En Swift, la gestion des erreurs est implémentée via le protocole Error (anciennement ErrorType). Tout type conforme à Error peut être levé via l'opérateur throw. Une fonction qui peut lever une erreur est marquée par le mot-clé throws dans sa signature. L'appel d'une telle fonction nécessite le préfixe try (pour try-catch explicite), try? (résultat optionnel) ou try! (exécution forcée sans gestion d'erreur).

swift
enum NetworkError: Error {
    case noConnection
    case serverError(code: Int)
    case timeout
}

func fetchUser(id: Int) throws -> User {
    guard isConnected() else {
        throw NetworkError.noConnection
    }
    let data = try performRequest(path: "/users/\(id)")
    return try decodeUser(from: data)
}

do {
    let user = try fetchUser(id: 42)
    updateUI(user)
} catch NetworkError.noConnection {
    showOfflineAlert()
} catch let error as NetworkError {
    showError("Réseau " + error.localizedDescription)
} catch {
    showGenericError()
}

L'enum NetworkError implémente le protocole Error, définissant trois cas : noConnection, serverError avec un code et timeout. La fonction fetchUser est marquée throws : elle vérifie d'abord la connexion, puis effectue la requête et l'analyse. Dans le bloc do-catch, trois catch traitent différents scénarios : le cas spécifique noConnection, le type général NetworkError et toutes les autres erreurs. Cela permet d'afficher à l'utilisateur des messages différents selon le type de problème.

Try-Catch dans Kotlin

Kotlin a hérité de try-catch-finally de Java mais a ajouté une différence importante : en Kotlin, try-catch est une expression, et non une instruction. Cela signifie que le résultat d'un bloc try ou catch peut être assigné à une variable. La dernière expression du bloc try devient le résultat en cas de succès, la dernière expression du catch — en cas d'erreur. Si l'erreur n'est traitée par aucun catch, l'exception remonte dans la pile.

kotlin
sealed class Result<out T> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Throwable) : Result<Nothing>()
}

fun loadData(): Result<List<Item>> {
    return try {
        val response = api.getItems()
        Result.Success(response.toList())
    } catch (e: HttpException) {
        Log.e("HTTP ", e)
        Result.Error(e)
    } catch (e: IOException) {
        Log.e("Réseau ", e)
        Result.Error(e)
    }
}

Dans l'exemple, sealed class Result encapsule une réponse réussie ou une erreur. La fonction loadData utilise try-catch comme expression : en cas de succès, elle retourne Result.Success, en cas de HttpException ou IOException — Result.Error avec journalisation. Cette approche permet à l'appelant de traiter les erreurs sans exceptions — via une expression when sur le type Result. C'est particulièrement pratique dans Jetpack Compose pour afficher différents états d'interface (Loading, Success, Error) via StateFlow et collectAsState.

Try-Catch dans Dart et Flutter

Dart prend en charge try-catch-finally avec une syntaxe similaire à Java, mais avec l'ajout d'une clause on pour filtrer par type d'exception sans spécifier de variable. C'est pratique lorsque l'exception elle-même n'est pas nécessaire — seul son type importe. Dart prend également en charge un bloc catch à deux paramètres : l'objet exception et StackTrace, utile pour journaliser la chaîne d'appels complète.

dart
import 'dart:io';
import 'dart:convert';

class UserRepository {
    Future<User> fetchUser(String id) async {
        try {
            final client = HttpClient();
            final request = await client.getUrl(
                Uri.parse('https://api.example.com/users/$id')
            );
            final response = await request.close();
            final body = await response.transform(utf8.decoder).join();
            return User.fromJson(json.decode(body));
        } on SocketException catch (e, stackTrace) {
            log("No internet", e, stackTrace);
            throw AppException("Connection failed");
        } on FormatException {
            throw AppException("Invalid response format");
        } finally {
            client.close();
        }
    }
}

SocketException est capturée avec l'objet exception et StackTrace pour une journalisation détaillée, puis relancée comme AppException. FormatException est capturée sans variable — il suffit de savoir que le format de la réponse est incorrect. Le bloc finally garantit la fermeture de HttpClient, évitant les fuites de sockets. Dans Flutter, cette approche est particulièrement importante pour les tests de Widget, où les exceptions non traitées dans State.initState provoquent l'échec de toute la session de test.

Erreurs fréquentes avec Try-Catch

Même les développeurs expérimentés commettent des erreurs avec try-catch qui entraînent des fuites mémoire, des bugs cachés ou un comportement inapproprié de l'application. Examinons les cinq problèmes les plus courants dans le développement mobile.

Bloc catch vide

Le catch vide est l'une des pires pratiques. L'exception est avalée, l'application continue de fonctionner dans un état incorrect et le développeur ne sait jamais qu'il y a un problème. Au moins, journalisez toujours l'exception. En Kotlin, utilisez catch(e: Exception) { Log.e(...) }, en Swift — catch { print($0) }. En Dart, un catch minimalement acceptable doit appeler debugPrint ou écrire dans Crashlytics.

Catch trop large

Capturer toutes les exceptions via catch (Exception e) sans distinguer les types cache des erreurs inattendues — NullPointerException, OutOfMemoryError, StackOverflowError. Ne capturez que les types que vous attendez et pouvez traiter. Pour tout le reste, autorisez la propagation vers le haut. Dans le développement mobile, des catch spécifiques pour IOException, TimeoutException, AuthException donnent des messages plus significatifs à l'utilisateur.

Ignorer finally

Les ressources — fichiers, sockets, curseurs de BD, animations — doivent être libérées dans finally ou dans un bloc use (AutoCloseable). Les développeurs oublient souvent de fermer les ressources lorsqu'une exception se produit, ce qui entraîne des fuites. En Kotlin, utilisez .use { } pour les ressources Closeable, en Swift — defer { }, en Dart — await using du package async. Le bloc finally garantit la libération même si une exception est levée à l'intérieur de catch.

Exceptions dans les threads et coroutines

Dans le code asynchrone, try-catch ne capture pas les exceptions provenant d'autres threads. En Kotlin Coroutines, utilisez CoroutineExceptionHandler ou SupervisorJob. En Swift async/await — do-catch dans Task. En Flutter — runZonedGuarded pour la capture globale. Ignorer cette règle est la cause de crashs difficiles à reproduire en production.

Blocage de l'UI lors d'une exception

La gestion des exceptions ne doit pas bloquer indéfiniment l'interface utilisateur. Affichez à l'utilisateur un message spécifique et donnez-lui la possibilité de réessayer l'opération. Une Snackbar avec un bouton Retry dans Kotlin/Compose, UIAlertController avec action dans Swift, SnackBar avec action dans Flutter — une UX minimalement suffisante pour les erreurs réseau ou serveur. Évitez les boîtes de dialogue génériques « Une erreur est survenue » sans options de récupération.

Questions fréquentes

Quelle est la différence entre try-catch et Result Type ?

Try-catch utilise les exceptions et le déroulement de pile pour la gestion des erreurs, ce qui peut être coûteux en performances lorsqu'il y a beaucoup d'erreurs. Result Type est un type conteneur (Success ou Failure) traité par filtrage de motif (pattern matching) sans déroulement de pile, plus efficace pour les erreurs attendues.

Doit-on utiliser finally dans chaque try-catch ?

Finally est obligatoire si le bloc try ouvre des ressources (fichiers, sockets, curseurs) qui doivent être fermées. Si aucune ressource n'est ouverte, finally n'est pas nécessaire. Dans les langages modernes, utilisez AutoCloseable/use/defer pour la fermeture automatique des ressources sans finally. Le bloc use dans Kotlin et Swift remplace finally pour les objets Closeable.

Try-catch peut-il être lent ?

Dans le flux normal (sans exceptions), try-catch n'affecte pratiquement pas les performances — la JVM et le compilateur Swift optimisent ce cas. Mais lorsqu'une exception est levée, le déroulement de pile se produit, ce qui peut prendre 10–100 μs selon la profondeur de la pile. N'utilisez pas les exceptions pour le contrôle de flux — c'est un anti-patron.

Comment gérer les erreurs dans Kotlin Coroutines ?

Dans les coroutines, utilisez try-catch à l'intérieur de coroutineScope ou CoroutineExceptionHandler pour la capture globale. SupervisorJob empêche l'annulation de la coroutine parente en cas d'échec d'une coroutine enfant. Pour launch, utilisez CoroutineExceptionHandler, pour async — try-catch autour de await().

Quel est le mieux : plusieurs catch ou un seul catch avec if-else ?

Plusieurs catch sont préférables : le code se lit linéairement, chaque bloc traite un type d'exception. Un seul catch avec if-else est plus difficile à maintenir et il est facile de manquer un nouveau type d'exception. En Swift, plusieurs catch sont obligatoires pour le traitement exhaustif de enum Error, en Kotlin il n'y a pas de restrictions, mais la meilleure pratique est un catch séparé par type.

Résumé

  • Try-Catch est une construction de capture d'exceptions avec blocs try, catch et finally optionnel pour une libération garantie des ressources
  • Mécanisme de fonctionnement — déroulement de pile lors d'une exception avec recherche du catch approprié par type d'erreur
  • Dans Swift on utilise do-catch avec enum Error, try? pour un résultat optionnel et try! pour un succès garanti
  • Dans Kotlin try-catch est une expression dont le résultat peut être assigné à une variable, pratique avec sealed class Result
  • Dans Dart prend en charge la clause on pour filtrer par type sans variable et finally pour fermer HttpClient
  • Erreurs fréquentes : catch vide, catch trop large, ignorer finally et absence de traitement dans les coroutines
  • Utilisez try-catch pour les erreurs inattendues, Result Type — pour les scénarios attendus avec échec possible

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