Entrees/Sorties Console et Gestion des References en Java

Maitrisez la lecture d'entrees utilisateur avec BufferedReader, Scanner et System.console(). Decouvrez les SoftReference et PhantomReference pour une gestion memoire optimisee en Java.

Mahmoud DEVO
Mahmoud DEVO
December 27, 2025 7 min read
Entrees/Sorties Console et Gestion des References en Java

Entrees/Sorties Console et Gestion des References en Java

Introduction

La gestion des entrees/sorties console est une competence fondamentale pour tout developpeur Java. Que ce soit pour creer des applications en ligne de commande, des outils de debug ou des scripts d’automatisation, savoir lire les entrees utilisateur et afficher des donnees formatees est essentiel.

Dans ce tutoriel complet, nous explorerons trois approches differentes pour lire les entrees utilisateur : BufferedReader, Scanner et System.console(). Chaque methode a ses avantages et cas d’utilisation specifiques. Nous aborderons egalement les concepts avances de gestion memoire avec les references SoftReference et PhantomReference, qui permettent un controle fin de la collecte des dechets (Garbage Collection).

Ce que vous allez apprendre :

  • Les trois methodes principales pour lire les entrees utilisateur en Java
  • Comment formater et afficher des tableaux dans la console
  • La difference entre SoftReference, WeakReference et PhantomReference
  • Les bonnes pratiques pour une gestion memoire efficace

Lecture d’entrees utilisateur avec BufferedReader

BufferedReader est la methode classique et performante pour lire des entrees utilisateur. Elle utilise un buffer interne qui optimise les operations de lecture, ce qui la rend ideale pour lire de grandes quantites de donnees.

Exemple de base

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class LectureBufferedReader {
    public static void main(String[] args) throws IOException {
        System.out.println("Veuillez taper votre nom et appuyer sur Entree.");
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String name = reader.readLine();
        System.out.println("Bonjour, " + name + " !");
        reader.close(); // Important : toujours fermer le reader
    }
}

Exemple avance avec gestion des exceptions

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class LectureBufferedReaderAvance {
    public static void main(String[] args) {
        // Utilisation du try-with-resources pour fermeture automatique
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
            System.out.print("Entrez votre age : ");
            String input = reader.readLine();
            int age = Integer.parseInt(input);
            System.out.println("Vous avez " + age + " ans.");
        } catch (IOException e) {
            System.err.println("Erreur de lecture : " + e.getMessage());
        } catch (NumberFormatException e) {
            System.err.println("Veuillez entrer un nombre valide.");
        }
    }
}

Avantages de BufferedReader :

  • Performance optimisee grace au buffer interne
  • Ideal pour lire de grandes quantites de texte
  • Controle fin sur la gestion des ressources

Lecture d’entrees utilisateur avec Scanner

Scanner est la methode la plus polyvalente et la plus simple a utiliser. Elle offre des methodes dediees pour lire differents types de donnees (entiers, decimaux, lignes, etc.).

Exemple de base

import java.util.Scanner;

public class LectureScanner {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Veuillez taper votre nom : ");
        String name = scanner.nextLine();
        System.out.println("Bonjour, " + name + " !");
        scanner.close();
    }
}

Lecture de differents types de donnees

import java.util.Scanner;

public class LectureScannerTypes {
    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            // Lecture d'un entier
            System.out.print("Entrez votre age : ");
            int age = scanner.nextInt();

            // Lecture d'un decimal
            System.out.print("Entrez votre taille (en metres) : ");
            double taille = scanner.nextDouble();

            // Consommer le retour a la ligne restant
            scanner.nextLine();

            // Lecture d'une chaine
            System.out.print("Entrez votre ville : ");
            String ville = scanner.nextLine();

            System.out.printf("Vous avez %d ans, mesurez %.2f m et habitez a %s%n",
                              age, taille, ville);
        }
    }
}

Validation des entrees avec Scanner

import java.util.Scanner;

public class ValidationEntree {
    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.print("Entrez un nombre entier : ");

            while (!scanner.hasNextInt()) {
                System.out.println("Ce n'est pas un entier valide !");
                scanner.next(); // Consommer l'entree invalide
                System.out.print("Entrez un nombre entier : ");
            }

            int nombre = scanner.nextInt();
            System.out.println("Vous avez entre : " + nombre);
        }
    }
}

Avantages de Scanner :

  • Simple et intuitif a utiliser
  • Methodes dediees pour chaque type de donnees
  • Validation integree avec hasNextXxx()

Lecture d’entrees utilisateur avec System.console()

System.console() est la methode ideale pour les applications en ligne de commande, notamment pour la lecture securisee de mots de passe. Attention : cette methode retourne null si l’application n’est pas executee depuis un terminal (par exemple, depuis un IDE).

Exemple de base

import java.io.Console;

public class LectureConsole {
    public static void main(String[] args) {
        Console console = System.console();

        if (console == null) {
            System.err.println("Aucune console disponible !");
            System.exit(1);
        }

        String name = console.readLine("Veuillez taper votre nom : ");
        console.printf("Bonjour, %s !%n", name);
    }
}

Lecture securisee de mot de passe

import java.io.Console;
import java.util.Arrays;

public class LectureMotDePasse {
    public static void main(String[] args) {
        Console console = System.console();

        if (console == null) {
            System.err.println("Console non disponible. Lancez depuis un terminal.");
            return;
        }

        String username = console.readLine("Nom d'utilisateur : ");
        char[] password = console.readPassword("Mot de passe : ");

        // Traitement de l'authentification
        if (authenticate(username, password)) {
            console.printf("Bienvenue, %s !%n", username);
        } else {
            console.printf("Authentification echouee.%n");
        }

        // IMPORTANT : effacer le mot de passe de la memoire
        Arrays.fill(password, ' ');
    }

    private static boolean authenticate(String username, char[] password) {
        // Logique d'authentification ici
        return username.equals("admin") && Arrays.equals(password, "secret".toCharArray());
    }
}

Avantages de System.console() :

  • Lecture securisee des mots de passe (pas d’echo a l’ecran)
  • Formatage integre avec printf() et readLine()
  • Pas besoin de gerer la fermeture des ressources

Affichage de tableaux formates

Le formatage de sortie est essentiel pour creer des interfaces console lisibles. Java offre plusieurs options via System.out.format(), String.format() et PrintWriter.format().

Syntaxe des specificateurs de format

SpecificateurDescriptionExemple
%sChaine de caracteres"texte"
%dEntier decimal42
%fNombre decimal3.14
%nNouvelle ligne
%-10sAligne a gauche, 10 caracteres"texte "
%10sAligne a droite, 10 caracteres" texte"

Exemple de tableau formate

public class AffichageTableau {
    public static void main(String[] args) {
        String[] noms = {"Alice", "Bob", "Charlie", "Diana"};
        int[] ages = {25, 30, 35, 28};
        double[] salaires = {45000.50, 52000.75, 61000.00, 48500.25};

        // En-tete du tableau
        String format = "| %-10s | %5s | %12s |%n";
        System.out.format("+------------+-------+--------------+%n");
        System.out.format(format, "Nom", "Age", "Salaire");
        System.out.format("+------------+-------+--------------+%n");

        // Donnees
        for (int i = 0; i < noms.length; i++) {
            System.out.format("| %-10s | %5d | %,12.2f |%n",
                              noms[i], ages[i], salaires[i]);
        }

        System.out.format("+------------+-------+--------------+%n");
    }
}

Sortie :

+------------+-------+--------------+
| Nom        |   Age |      Salaire |
+------------+-------+--------------+
| Alice      |    25 |    45 000,50 |
| Bob        |    30 |    52 000,75 |
| Charlie    |    35 |    61 000,00 |
| Diana      |    28 |    48 500,25 |
+------------+-------+--------------+

Gestion avancee de la memoire : les References en Java

Java propose quatre types de references, chacune avec un comportement different vis-a-vis du Garbage Collector. Comprendre ces references est essentiel pour optimiser la gestion memoire.

Hierarchie des references

TypeForceCollecte GCCas d’usage
Strong ReferenceForteJamais (tant que reference existe)Usage normal
SoftReferenceMoyenneQuand memoire insuffisanteCache memoire
WeakReferenceFaibleAu prochain passage du GCListeners, caches temporaires
PhantomReferenceAucuneApres finalisationNettoyage de ressources natives

SoftReference : Cache memoire intelligent

Les SoftReference sont ideales pour implementer des caches. L’objet est conserve tant que la memoire est suffisante, puis libere en cas de pression memoire.

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;

public class CacheSoftReference {
    private Map<String, SoftReference<byte[]>> cache = new HashMap<>();

    public void put(String key, byte[] data) {
        cache.put(key, new SoftReference<>(data));
    }

    public byte[] get(String key) {
        SoftReference<byte[]> ref = cache.get(key);
        if (ref != null) {
            byte[] data = ref.get();
            if (data != null) {
                return data;
            }
            // Reference collectee, supprimer l'entree
            cache.remove(key);
        }
        return null;
    }

    public static void main(String[] args) {
        CacheSoftReference imageCache = new CacheSoftReference();

        // Stocker une "image" de 1 Mo
        byte[] image = new byte[1024 * 1024];
        imageCache.put("photo1.jpg", image);

        // Recuperer l'image
        byte[] retrieved = imageCache.get("photo1.jpg");
        System.out.println("Image recuperee : " + (retrieved != null));
    }
}

WeakReference : References temporaires

Les WeakReference sont collectees au prochain passage du GC, meme si la memoire est suffisante. Utiles pour les listeners ou metadata.

import java.lang.ref.WeakReference;
import java.util.WeakHashMap;

public class ExempleWeakReference {
    public static void main(String[] args) {
        // Reference forte
        Object objetFort = new Object();

        // Reference faible vers le meme objet
        WeakReference<Object> refFaible = new WeakReference<>(objetFort);

        System.out.println("Avant GC : " + refFaible.get()); // Non null

        // Supprimer la reference forte
        objetFort = null;

        // Forcer le GC
        System.gc();

        // La reference faible est maintenant null
        System.out.println("Apres GC : " + refFaible.get()); // Probablement null
    }
}

PhantomReference : Nettoyage post-mortem

Les PhantomReference permettent d’executer des actions de nettoyage apres que l’objet a ete finalise mais avant que sa memoire soit liberee.

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class ExemplePhantomReference {
    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        Object objet = new Object();

        PhantomReference<Object> phantomRef = new PhantomReference<>(objet, queue);

        // get() retourne TOUJOURS null pour PhantomReference
        System.out.println("Phantom get() : " + phantomRef.get()); // null

        // Supprimer la reference forte
        objet = null;
        System.gc();

        // Attendre que la reference soit mise dans la queue
        Thread.sleep(100);

        // Verifier si l'objet a ete collecte
        if (queue.poll() != null) {
            System.out.println("L'objet a ete collecte, nettoyage possible.");
        }
    }
}

Bonnes Pratiques

Pour les entrees/sorties console

  1. Utilisez try-with-resources : Garantit la fermeture automatique des ressources.
try (Scanner scanner = new Scanner(System.in)) {
    // Utilisation du scanner
} // Fermeture automatique
  1. Validez toujours les entrees utilisateur : Ne faites jamais confiance aux donnees entrees.
while (!scanner.hasNextInt()) {
    System.out.println("Entree invalide !");
    scanner.next();
}
  1. Gerez les exceptions : Anticipez les erreurs de lecture et de parsing.

  2. Choisissez la bonne methode :

    • BufferedReader : Lecture de fichiers ou grandes quantites de texte
    • Scanner : Applications interactives avec types varies
    • System.console() : Applications securisees (mots de passe)

Pour la gestion des references

  1. Preferez les references fortes par defaut : N’utilisez les references speciales que si necessaire.

  2. Utilisez SoftReference pour les caches : Ideal pour les donnees recalculables.

  3. Nettoyez les WeakReference : Verifiez toujours si get() retourne null.

  4. Utilisez ReferenceQueue : Pour etre notifie de la collecte des objets.

Pieges Courants

Piege 1 : Scanner et le retour a la ligne

// PROBLEME : nextInt() ne consomme pas le retour a la ligne
Scanner sc = new Scanner(System.in);
int age = sc.nextInt();
String nom = sc.nextLine(); // Lit une chaine vide !

// SOLUTION : Consommer le retour a la ligne
int age = sc.nextInt();
sc.nextLine(); // Consommer le \n
String nom = sc.nextLine(); // Maintenant ca fonctionne

Piege 2 : System.console() retourne null

// PROBLEME : Plante dans un IDE
String input = System.console().readLine(); // NullPointerException !

// SOLUTION : Verifier avant d'utiliser
Console console = System.console();
if (console == null) {
    System.err.println("Utilisez un terminal pour cette application.");
    return;
}

Piege 3 : Confondre WeakReference et SoftReference

// WeakReference : Collectee au prochain GC
// Utiliser pour : Listeners, metadata temporaires

// SoftReference : Collectee seulement si memoire insuffisante
// Utiliser pour : Caches de donnees

Piege 4 : Oublier de fermer les ressources

// PROBLEME : Fuite de ressources
BufferedReader reader = new BufferedReader(...);
String line = reader.readLine();
// Oubli de reader.close() !

// SOLUTION : try-with-resources
try (BufferedReader reader = new BufferedReader(...)) {
    String line = reader.readLine();
} // Fermeture automatique

Conclusion

Dans cet article, nous avons explore les concepts fondamentaux des entrees/sorties console en Java ainsi que la gestion avancee de la memoire avec les differents types de references.

Points cles a retenir :

  1. Trois methodes de lecture : BufferedReader (performance), Scanner (polyvalence), System.console() (securite)

  2. Formatage de sortie : Utilisez System.out.format() avec les specificateurs (%s, %d, %f) pour des affichages professionnels

  3. Gestion memoire : Les references Soft, Weak et Phantom offrent un controle fin sur le Garbage Collector

  4. Bonnes pratiques : Toujours utiliser try-with-resources, valider les entrees, et choisir le bon type de reference

Ces competences sont essentielles pour developper des applications Java robustes, que ce soit des outils en ligne de commande, des systemes de cache intelligents ou des applications necessitant une gestion memoire optimisee.

Pour aller plus loin

Exercices pratiques

  1. Debutant : Creer un programme qui lit une liste de noms et les affiche dans un tableau formate

  2. Intermediaire : Implementer un cache d’images utilisant SoftReference avec une limite de taille

  3. Avance : Creer un systeme de logging qui utilise PhantomReference pour nettoyer les ressources fichier apres collecte des objets Logger

En pratiquant ces exercices, vous maitriserez les entrees/sorties console et la gestion memoire en Java.

Advertisement

In-Article Ad

Dev Mode

Share this article

Mahmoud DEVO

Mahmoud DEVO

Senior Full-Stack Developer

I'm a passionate full-stack developer with 10+ years of experience building scalable web applications. I write about Vue.js, Node.js, PostgreSQL, and modern DevOps practices.

Enjoyed this article?

Subscribe to get more tech content delivered to your inbox.

Related Articles