CodeGym /Cours /JAVA 25 SELF /Utilisation de try-with-resources : fermeture automatique...

Utilisation de try-with-resources : fermeture automatique des ressources

JAVA 25 SELF
Niveau 36 , Leçon 4
Disponible

1. Introduction

Travailler avec des fichiers en Java (et pas seulement !) signifie toujours manipuler des ressources externes. Lorsque vous ouvrez un fichier, le système d’exploitation alloue à votre programme un « descripteur » — un identifiant spécial qui permet de lire et d’écrire dans le fichier. Le nombre de descripteurs est limité : si vous ne fermez pas les fichiers, le programme peut rapidement « consommer » toutes les ressources disponibles et commencer à lancer des erreurs mystérieuses de type "Too many open files".

De plus, si un fichier n’est pas fermé, il peut rester verrouillé pour d’autres programmes. Par exemple, vous avez ouvert un fichier en écriture, vous avez oublié de le fermer, et maintenant ni vous ni quiconque ne pouvez le modifier ou le supprimer. Une sorte de « prise d’otages éternelle » dans le monde des systèmes de fichiers.

Exemple concret

FileInputStream fis = new FileInputStream("data.txt");
int b = fis.read();
// ... on fait quelque chose, puis on oublie fis.close()

Si vous n’appelez pas la méthode close(), le fichier restera « en suspens » jusqu’à la fin de l’exécution du programme. Dans les grandes applications, cela peut entraîner des fuites de ressources et même un plantage de l’application.

2. Méthode ancienne : finally + close()

Avant Java 7, la façon classique de garantir la fermeture d’un fichier ressemblait à ceci :

FileInputStream fis = null;
try {
    fis = new FileInputStream("data.txt");
    // lisons le fichier
    int b = fis.read();
    // ...
} catch (IOException e) {
    System.out.println("Erreur lors de la lecture du fichier: " + e.getMessage());
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            System.out.println("Erreur lors de la fermeture du fichier: " + e.getMessage());
        }
    }
}

Inconvénients de cette approche

  • Il est facile d’oublier le bloc finally et de provoquer une fuite de ressources.
  • Beaucoup de code superflu, surtout s’il y a plusieurs flux.
  • Si une exception se produit pendant la fermeture, il faut aussi la capturer séparément.
  • Le code devient lourd et moins lisible.

3. Approche moderne : try-with-resources

Heureusement, à partir de Java 7, une syntaxe résout ces problèmes de manière élégante et automatique — try-with-resources.

À quoi cela ressemble

try (FileInputStream fis = new FileInputStream("data.txt")) {
    int b = fis.read();
    // on travaille avec le fichier
} catch (IOException e) {
    System.out.println("Erreur lors de l’utilisation du fichier: " + e.getMessage());
}
// Ici, fis est déjà fermé automatiquement !

Point clé : toutes les ressources déclarées entre parenthèses après try seront automatiquement fermées à la fin du bloc — même si une exception survient au milieu. Pas besoin d’écrire finally, pas besoin d’attraper séparément les erreurs de fermeture — Java s’occupe de tout pour vous.

Quelles classes peut-on utiliser avec try-with-resources ?

Toute classe qui implémente l’interface AutoCloseable (ou l’historique Closeable). C’est le cas de la plupart des flux standard d’E/S : FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, Scanner, PrintWriter et bien d’autres.

4. Syntaxe de try-with-resources : détails et exemples

Une ressource

try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"))) {
    String line = reader.readLine();
    System.out.println(line);
} catch (IOException e) {
    System.out.println("Erreur: " + e.getMessage());
}
// reader est fermé automatiquement !

Ressources multiples

On peut déclarer plusieurs ressources séparées par des points-virgules :

try (
    BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
    BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))
) {
    String line;
    while ((line = reader.readLine()) != null) {
        writer.write(line);
        writer.newLine();
    }
} catch (IOException e) {
    System.out.println("Erreur lors de la copie: " + e.getMessage());
}
// les deux flux sont fermés !

Ordre de fermeture : les ressources sont fermées dans l’ordre inverse de leur déclaration. writer.close() est appelé en premier, puis reader.close(). C’est important si un flux dépend d’un autre.

Utilisation avec des classes personnalisées

Si vous écrivez votre propre classe qui travaille avec des ressources, implémentez simplement l’interface AutoCloseable :

class MyResource implements AutoCloseable {
    public void doSomething() {
        System.out.println("On travaille avec la ressource !");
    }

    @Override
    public void close() {
        System.out.println("Ressource fermée !");
    }
}

try (MyResource res = new MyResource()) {
    res.doSomething();
}
// À la sortie du bloc, on affichera : "Ressource fermée !"

5. Comment cela fonctionne : schéma

flowchart TD
    A[Ouverture de la ressource dans try-with-resources] --> B{Une exception s’est-elle produite dans le bloc try ?}
    B -- Non --> C[La ressource est fermée automatiquement]
    B -- Oui --> D[La ressource est fermée automatiquement]
    D --> E[L’exception est propagée]
    C --> F[Le programme continue son exécution]

Conclusion : qu’il y ait une erreur ou non, la ressource sera toujours fermée !

6. Exemples : réécrire le code « à la moderne »

Avant (ancien style) :

BufferedReader reader = null;
try {
    reader = new BufferedReader(new FileReader("input.txt"));
    String line = reader.readLine();
    System.out.println(line);
} catch (IOException e) {
    System.out.println("Erreur: " + e.getMessage());
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException e) {
            System.out.println("Erreur lors de la fermeture: " + e.getMessage());
        }
    }
}

Après (try-with-resources) :

try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"))) {
    String line = reader.readLine();
    System.out.println(line);
} catch (IOException e) {
    System.out.println("Erreur: " + e.getMessage());
}
// C’est tout, pas de finally !

7. Que se passe-t-il en cas d’erreur lors de la fermeture ?

Parfois, l’opération de fermeture d’une ressource peut elle-même lancer une exception (par exemple, si le fichier disparaît soudainement). Avec try-with-resources, ces exceptions ne sont pas perdues : si une exception s’est déjà produite dans le bloc try et qu’une seconde survient lors de la fermeture de la ressource, cette seconde sera ajoutée comme exception « supprimée » (suppressed exception) à la principale. Vous pouvez la voir à l’aide de la méthode Throwable.getSuppressed().

Exemple

try (MyResource res = new MyResource()) {
    throw new IOException("Erreur dans le bloc try");
} catch (IOException e) {
    System.out.println("Erreur principale: " + e.getMessage());
    for (Throwable suppressed : e.getSuppressed()) {
        System.out.println("Exception supprimée: " + suppressed.getMessage());
    }
}

8. Quelles classes prennent en charge try-with-resources ?

C’est simple : toute classe qui implémente l’interface AutoCloseable. Voici quelques-unes des classes standard :

Classe Rôle
FileInputStream
Lecture d’octets depuis un fichier
FileOutputStream
Écriture d’octets dans un fichier
FileReader/FileWriter
Lecture/écriture de texte
BufferedReader/Writer
Mise en tampon des flux
PrintWriter
Écriture de texte formaté
Scanner
Lecture de données depuis un fichier/la console
ObjectInputStream/Output
Sérialisation/désérialisation
ZipInputStream/Output
Manipulation d’archives ZIP
Socket, ServerSocket
Connexions réseau

Si vous utilisez des bibliothèques tierces — consultez la documentation : s’il existe une méthode close(), il y a de fortes chances que la classe prenne en charge try-with-resources.

9. Conseils et subtilités utiles

On peut déclarer des variables en dehors de try (depuis Java 9) : on peut utiliser des ressources déjà déclarées si elles sont final ou « effectively final » :

BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
try (reader) {
    // ...
}

Ne se limite pas aux fichiers : try-with-resources est pratique pour toute ressource : connexions réseau, bases de données, tout objet possédant une méthode close().

N’ignorez pas les exceptions : même avec try-with-resources, n’oubliez pas d’attraper et de traiter les exceptions — ce n’est pas une panacée, juste une manière pratique d’éviter les fuites.

Ne fermez pas la ressource manuellement à l’intérieur du try : ce n’est pas nécessaire — Java s’en charge ! Si vous appelez close() manuellement et que le bloc try se termine ensuite, il y aura une tentative de fermeture d’une ressource déjà fermée. En général c’est sans danger, mais cela peut prêter à confusion.

10. Erreurs typiques lors de l’utilisation de try-with-resources

Erreur n°1 : oublier d’utiliser try-with-resources tout court. Si vous écrivez encore finally { resource.close(); } — soit vous êtes resté en 2011, soit vous n’avez pas lu cette leçon ! Utilisez la syntaxe moderne.

Erreur n°2 : déclarer la ressource hors du try, puis simplement l’utiliser dedans. Un tel code ne fermera pas la ressource automatiquement :

BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
try {
    // ... on utilise reader
} finally {
    // Et ici, on a oublié de le fermer !
}

Erreur n°3 : appeler close() manuellement à l’intérieur du bloc try. Ce n’est pas critique, mais c’est redondant et peut conduire à une double fermeture. Faites confiance à Java.

Erreur n°4 : n’attraper que Exception en ignorant les spécificités d’E/S. Il vaut mieux attraper des exceptions précises (FileNotFoundException, IOException) pour fournir des messages clairs à l’utilisateur.

Erreur n°5 : ne pas traiter les exceptions supprimées. Si une erreur survient lors de la fermeture de la ressource, elle peut être « supprimée ». Si vous analysez les erreurs, n’oubliez pas getSuppressed().

1
Étude/Quiz
Lecture et écriture de fichiers, niveau 36, leçon 4
Indisponible
Lecture et écriture de fichiers
Lecture et écriture de fichiers
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION