
Le projet continue de progresser. Tandis que vous avez eu quelques jours de repos, Marc a eu l’occasion de faire progresser le projet. Vous consultez le code pour le rĂ©cupĂ©rer.Â
Vous n’êtes pas déçu par le résultat, Marc sait y faire pour coder un programme de qualité !
Une fois le programme exécuté le résultat est le suivant :

La modélisation est la suivante :

C’est sympa, mais cela manque un peu d’interaction. Marc prévoit la mise en place d’une fonctionnalité où l’utilisateur doit choisir entre afficher les idées de constructions ou afficher le nombre de blocs pour chaque type de bloc.
De plus, il aimerait qu’on puisse écrire dans un fichier le résultat de certaines opérations de l’utilisateur.
Comment faire pour récupérer la saisie d’un utilisateur ? Et je n’ai jamais manipulé de fichiers non plus !
Récupérer une saisie utilisateur ou écrire dans un fichier revient à traiter du thème de l’envoie et la réception de données par notre programme. Pour mener à bien un échange de données il faut une source et un destinataire, notez quelques exemples :
 | Source | Destinataire |
Lecture des données d’un fichier | Fichier | Programme |
Écriture des données dans un fichier | Programme | Fichier |
Lecture des données d’une console | Console | Programme |
Écriture des données dans une console | Programme | Console |
Un de nos deux objectifs est de récupérer la saisie d’un utilisateur, dans ce cas la console sera la source des données et le programme en sera le destinataire.
Pour l’autre objectif où l’on veut écrire le résultat de certaines opérations sur les blocs de l’utilisateur dans un fichier alors le programme est la source et le fichier le destinataire.
Techniquement pour réaliser ces opérations d'envoi / réception, nous pouvons utiliser les flux en Java. Vous entendrez principalement parler de Streams qui est la terminologie couramment utilisée.
Comme vu précédemment, un programme peut être un destinataire et une source, il existe donc :
des flux d’entrées, le programme reçoit une donnée (destinataire).
des flux de sorties, le programme envoie une donnée (source).
Comme à son habitude le langage Java va nous offrir des classes pour manipuler ces flux. Le package java.io contient ses différentes classes.
Il y a toute une nomenclature associée aux flux. Tout d’abord on peut diviser les classes permettant de gérer les flux en deux catégories :
Celle pour gérer des flux d’octets.
Celle pour gĂ©rer des flux de caractères.Â
Concentrons-nous sur les flux de caractères, ces derniers sont divisés en deux catégories :
Les flux de caractères d’écriture : Writer
Les flux de caractères de lecture : Reader
java.io.Reader et java.io.Writer sont deux classes abstraites qui seront implémentées par d’autres classes à utiliser en fonction du cas d’usage.
Pour remplir notre premier objectif, apprenons maintenant à manipuler la console pour savoir récupérer une saisie de l’utilisateur et ainsi lui permettre d’agir sur le comportement du programme.
Récupérer la saisie d’un utilisateur nécessite de savoir manipuler la console. Et sachez que vous savez déjà en partie le faire !
Comment ça ?
Et oui, voilà un moment que vous utilisez l’instruction  System.out.println() pour écrire dans la console. À chaque fois que vous l’avez fait votre programme était la source d’une donnée et la console le destinataire.
Plus concrètement, la classe System possède un attribut static nommé out de type java.io.PrintStream. Il s’agit de la classe pour écrire dans la console avec un flux d’octet et non de caractères. La classe System étant prête à l’emploi je ne peux que vous conseiller de l’utiliser.
Laissez-moi tout de même vous parlez de la classe java.io.PrintWriter qui peut également être utilisée pour écrire dans une console via un flux de caractères et non d’octet. Tout d’abord elle étend la classe abstraite java.io.Writer et regardez le code suivant :
Main.java
public class Main {
public static void main(String[] args) {
PrintWriter writer = new PrintWriter(System.out);
writer.println("Et un bloc par ci, un bloc par lĂ !");
writer.flush();
writer.close();
}
}Mais pourquoi la classe PrintWriter prend en paramètre System.out qui est un objet de type PrintStream ?
Car comme dit précédemment un caractère correspond à plusieurs octets (2 en l'occurrence) donc les flux de caractères sont une sorte de surcouche au flux d’octets, plus facilement compréhensible pour un développeur débutant.
Vis-à -vis du code précédent, nous pouvons noter deux points :
Pour que le texte soit écrit dans la console il faut appeler la méthode  flush() sur le flux.
Un flux s’ouvre en instanciant la classe mais se ferme Ă©galement grâce Ă la mĂ©thode  close() .Â
C’est un peu fastidieux, donc rassurez-vous je ne vais pas vous demander d’abandonner System.out.println qui est plus pratique.
Très bien, mais je ne sais toujours pas récupérer la saisie d’un utilisateur, non?
C’est vrai, passons maintenant au flux d’entrée avec la console ! Pour lire dans la console c’est la classe java.io.BufferedReader, qui de son côté étend la classe abstraite java.io.Reader.
Selon le même principe que pour PrintWriter, BufferedReader aura besoin de s’appuyer sur un flux d’octets. Notons le code suivant :
Main.java
public class Main {
public static void main(String[] args) {
BufferedReader fluxEntree = new BufferedReader(new InputStreamReader(System.in));
String saisieUtilisateur = fluxEntree.readLine();
System.out.println(saisieUtilisateur);
fluxEntree.close();
}
}A noter :
Nous construisons le flux d’octets entrants grâce à la classe java.io.InputStreamReader. Le constructeur de cette dernière prend en paramètre System.in qui est une instance de java.io.InputStream.
Ensuite le flux d’octets est passĂ© en paramètre du constructeur de java.io.BufferedReader.Â
La méthode  readLine() permet de récupérer un texte saisi dans la console et le renvoie sous forme d’objet java.lang.String que je décide ensuite d’afficher dans la console.
Le flux de caractères entrants doit également être fermé avec la méthodeclose .
La variable saisieUtilisateur peut maintenant être comparée à n’importe quelle valeur de notre choix et ainsi nous pouvons adapter le comportement de notre programme en fonction de la saisie de l’utilisateur.
Et si on applique ça à notre projet Epicrafter’s Journey, nous irions certainement dans la direction suivante :
public static void main(String[] args) throws IOException {
logger.info("Lancement du programme Epicrafter's Journey.");
try {
// Le programme commence avec un Kit de démarrage.
KitDemarrage kit = new KitDemarrage();
System.out.println("Vous possĂ©dez un kit de dĂ©marrage !");Â
System.out.println(
"Que souhaitez-vous afficher ?\n\t1 - Les idées de constructions. \n\t2 - Le nombre de blocs pour chaque type de blocs présent dans le kit");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String reponse = reader.readLine();
if (reponse.equals("1")) {
// code pour afficher les idées de constructions
} else if(reponse.equals("2")) {
// code pour affiche le nombre de blocs pour chaque type de blocs présent dans le kit
} else {
System.out.println("La valeur saisie n'est pas valide - tapez 1 ou 2.");
}
} catch (IllegalBlocException e) {
System.out.println("Impossible de construire le Kit de démarrage.");
}
logger.info("Arret du programme Epicrafter's Journey.");
}Finalement ce code ne comporte aucune complexité particulière tout en nous permettant d’adapter le comportement de notre programme selon une saisie réalisée par l’utilisateur.
Avant de conclure cette section, sachez que de nombreux dĂ©veloppeurs utilisent la classe java.util.Scanner pour lire Ă partir de la console grâce Ă ses nombreuses mĂ©thodes destinĂ©es Ă faciliter la lecture de la console. Â
On enchaîne avec le deuxième objectif fixé par Marc : écrire dans un fichier le résultat de certaines opérations qui ont été réalisées par l’utilisateur.
Dans cette démonstration, nous allons ajouter une méthode sauvegarder dans la classe KitDemarrage qui aura pour objectif d’écrire le contenu du kit dans un fichier.
Les points Ă retenir sont les suivants :
Pour écrire dans un fichier nous pouvons utiliser la classe java.io.BufferedWriter. Le constructeur de cette dernière a besoin d’une instance de java.io.FileWriter en paramètre.
La méthodewrite permet d’écrire dans le fichier.
Par défaut, le fichier est écrit à la racine du dossier du projet.
Il ne faut jamais oublier de .close(). Ce qui est ouvert doit être fermé.
Voici le code de la méthode sauvegarder réalisée durant la démonstration :
public void sauvegarder() {
StringBuilder builder = new StringBuilder();
builder.append("Kit de démarrage\n");
for(String motCle : motsCles) {
builder.append(motCle + " ");
}
try {
BufferedWriter writer = new BufferedWriter(new FileWriter("kit.txt"));
writer.write(builder.toString());
writer.close();
} catch (IOException e) {
logger.error("Impossible d'écrire dans le fichier");
}
}Notre code est composé de deux groupes d’instructions :
La création du texte à écrire dans le fichier grâce à un objet java.lang.StringBuilder : en l'occurrence c’est la liste des mots-clés que l’on souhaite sauvegarder.
L’écriture dans le fichier grâce à l’objet java.io.BufferedWriter et l’appel de la méthode write.
Il nous aura donc suffi de quelques lignes pour réaliser ce qui était attendu par Marc !
Ne nous arrêtons pas en si bon chemin, même si Marc ne nous l’a pas demandé, je vais vous montrer comment lire le contenu d’un fichier. La lecture d’un fichier ressemble à la lecture de la console, notez ce code :
public void charger() {
try (BufferedReader reader = new BufferedReader(new FileReader("kit.txt"))) {
String line = null;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
logger.error("Le fichier kit.txt n'existe pas.");
} catch (IOException e) {
logger.error("Impossible de lire le fichier kit.txt");
}
}Comme lorsque nous avons récupéré la saisie d’un utilisateur dans la console, nous utilisons la classe java.io.BufferedReader et la méthode readLine mais cette fois-ci la boucle while nous permettra de lire toutes les lignes du fichier. La boucle va s’arrêter lorsque la méthode readLine renverra null, ce qui signifie qu’il n’y a plus de lignes à lire.
De plus, j’attire votre attention sur la syntaxe du try. Cette notation est un try-with-resources ! IntĂ©grĂ©e Ă partir de Java 7, cette syntaxe nous assure que le flux sera fermĂ© mĂŞme si une exception est dĂ©clenchĂ©e après l’ouverture du flux. Très pratique du coup !Â
En conclusion, non seulement les objectifs fixés par Marc ont été atteints mais en plus vous êtes en mesure de lire le contenu d’un fichier.

Vous recevez enfin la tâche avec la nouvelle fonctionnalité prévue par Marc :
ID de la tâche : 9
Nom de la tâche : Choix de l’utilisateur lors de l’utilisation du Kit
Description de la tâche :Â
Lorsque le programme démarre, un kit de démarrage est fourni à l’utilisateur. Actuellement il est affiché à l’utilisateur tant les idées de constructions que le nombre de blocs de chaque type présent dans le kit.
L’utilisateur devra avoir le choix entre afficher l’une ou l'autre des informations.
Vous vous lancez dans la réalisation de cette tâche !
La classe Main devra être modifiée.
Affichez une question “Que souhaitez-vous afficher ? 1 - Les idées de constructions. 2 - Le nombre de blocs pour chaque type de blocs présent dans le kit”.
Utilisez un BufferedReader comme vu dans le chapitre pour lire la valeur qui sera saisie, en l'occurrence 1 ou 2.
Utilisez une structure conditionnelle pour adapter le code en fonction de la valeur obtenue.
Java possède de nombreuses classes pour gérer les flux entrants et sortants.
java.io.BufferedReader permet de lire la saisie d’un utilisateur dans la console console.
java.io.BufferedReader permet également de lire le contenu d’un fichier.
java.io.BufferedWriter permet d’écrire dans un fichier.
java.io.PrintWriter permet d’écrire dans la console bien que nous puissions également le faire avec  System.out.println()
Continuons à explorer les bonnes pratiques professionnelles en allégeant le code grâce au lambda dans le prochain chapitre !