Table of Contents
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()etreadLine() - 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
| Specificateur | Description | Exemple |
|---|---|---|
%s | Chaine de caracteres | "texte" |
%d | Entier decimal | 42 |
%f | Nombre decimal | 3.14 |
%n | Nouvelle ligne | |
%-10s | Aligne a gauche, 10 caracteres | "texte " |
%10s | Aligne 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
| Type | Force | Collecte GC | Cas d’usage |
|---|---|---|---|
| Strong Reference | Forte | Jamais (tant que reference existe) | Usage normal |
| SoftReference | Moyenne | Quand memoire insuffisante | Cache memoire |
| WeakReference | Faible | Au prochain passage du GC | Listeners, caches temporaires |
| PhantomReference | Aucune | Apres finalisation | Nettoyage 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
- Utilisez try-with-resources : Garantit la fermeture automatique des ressources.
try (Scanner scanner = new Scanner(System.in)) {
// Utilisation du scanner
} // Fermeture automatique
- Validez toujours les entrees utilisateur : Ne faites jamais confiance aux donnees entrees.
while (!scanner.hasNextInt()) {
System.out.println("Entree invalide !");
scanner.next();
}
-
Gerez les exceptions : Anticipez les erreurs de lecture et de parsing.
-
Choisissez la bonne methode :
BufferedReader: Lecture de fichiers ou grandes quantites de texteScanner: Applications interactives avec types variesSystem.console(): Applications securisees (mots de passe)
Pour la gestion des references
-
Preferez les references fortes par defaut : N’utilisez les references speciales que si necessaire.
-
Utilisez SoftReference pour les caches : Ideal pour les donnees recalculables.
-
Nettoyez les WeakReference : Verifiez toujours si
get()retourne null. -
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 :
-
Trois methodes de lecture :
BufferedReader(performance),Scanner(polyvalence),System.console()(securite) -
Formatage de sortie : Utilisez
System.out.format()avec les specificateurs (%s,%d,%f) pour des affichages professionnels -
Gestion memoire : Les references
Soft,WeaketPhantomoffrent un controle fin sur le Garbage Collector -
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
- Documentation Oracle : java.io Package
- Documentation Oracle : java.lang.ref Package
- Article recommande : Garbage Collection Tuning Guide
Exercices pratiques
-
Debutant : Creer un programme qui lit une liste de noms et les affiche dans un tableau formate
-
Intermediaire : Implementer un cache d’images utilisant
SoftReferenceavec une limite de taille -
Avance : Creer un systeme de logging qui utilise
PhantomReferencepour 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.
In-Article Ad
Dev Mode
Tags
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
Optimisation des performances Java : finalisation, GC et benchmarking
Optimisez vos applications Java : evitez les pieges de finalize(), utilisez StringBuilder et creez des benchmarks fiables. Guide methodologique complet.
Manipuler les classes Java avec ASM et Javassist : bytecode, instrumentation et fichiers JAR
Apprenez a manipuler les classes Java avec ASM et Javassist : chargement, modification du bytecode, instrumentation et creation de fichiers JAR.
Synchronisation Java avec AtomicInteger : eviter la contention et optimiser les performances
Decouvrez comment utiliser les types atomiques Java (AtomicInteger, AtomicLong, AtomicReference, AtomicBoolean) pour reduire la contention, eviter les blocages et ameliorer les performances.