Keyboard shortcuts

Touchez ← ou → pour naviguer les chapitres

Touchez S ou / pour chercher dans le livre

Touchez ? pour afficher ce message

Touchez Esc pour masquer ce message

Accueil > Programmer avec Java > Les bases de Java >

Entrées et sorties à la console

Survol et attentes

Pour ajouter de l’interaction Ă  un programme, il faut donner la chance Ă  l’utilisateur de nous fournir une rĂ©ponse. Dans le contexte d’un programme qui se lance Ă  la console, cela veut dire capter les rĂ©ponses tapĂ©es par l’utilisateur au clavier. Dans cette leçon, nous allons voir comment faire ça en Java.

Définitions
Mot-clé new
un mot-clĂ© qui crĂ©e une nouvelle instance d’une classe (qui crĂ©e un objet). Ce mot-clĂ© est suivi par une mĂ©thode spĂ©ciale de la classe appelĂ©e le constructeur. Chaque classe dĂ©finit son propre constructeur, alors il faut connaĂźtre les dĂ©tails de la classe pour crĂ©er des objets de cette classe. Votre EDI vous aide avec ces dĂ©tails. La dĂ©claration complĂšte d’un nouvel objet est Type nom = new Type(arguments, ...);.
Classe Scanner
une classe qui nous permet de lire une source de texte comme la console, un String ou un fichier de texte. Un objet de type Scanner a accĂšs Ă  plusieurs mĂ©thodes d’instance pour retourner diffĂ©rents types de donnĂ©es. Un Scanner saisie toujours du texte, donc les mĂ©thodes comme nextInt() et nextDouble() convertissent le texte en nombre et peuvent planter si le format des caractĂšres saisis ne correspond pas au type attendu. C’est pourquoi il y a aussi des mĂ©thodes comme hasNextInt() et hasNextDouble() pour valider le format avant de tenter une conversion.
Classe Locale
une classe qui permet de spĂ©cifier un ensemble de formats rĂ©gionaux, notamment celui des nombres dĂ©cimaux. Par dĂ©faut, le format dĂ©pend du systĂšme d’exploitation donc le programme se comportera diffĂ©remment sur diffĂ©rents ordinateurs. Pour Ă©viter des erreurs de conversion, on peut spĂ©cifier un Locale pour chaque Scanner en utilisant la mĂ©thode useLocale().
Objet System.in
un objet de type InputStream qui reprĂ©sente l’entrĂ©e standard du systĂšme d’exploitation, gĂ©nĂ©ralement la console. L’avantage est qu’il est toujours dĂ©fini (ça fonctionne toujours). Le dĂ©savantage est que Windows gĂšre les caractĂšres Unicode diffĂ©remment que le reste du monde, ce qui donne parfois des comportements inattendus et difficiles Ă  rĂ©soudre.
Invite de réponse
un message affichĂ© Ă  l’utilisateur pour lui indiquer ce qu’il doit saisir. C’est une bonne pratique de donner des invites de rĂ©ponse claires et spĂ©cifiques pour Ă©viter des erreurs de saisie. Des bonnes invites de rĂ©ponse rendent toujours l’intĂ©raction plus agrĂ©able pour l’utilisateur.

Liste des méthodes de Scanner les plus courantes :

  • next() : saisir le prochain mot (jusqu’à un espace, ignorant les espaces initiaux)
  • nextInt() : saisir le prochain mot et le convertir en int
  • nextDouble() : saisir le prochain mot et le convertir en double
  • hasNextInt() : vĂ©rifier si le prochain mot est un int
  • hasNextDouble() : vĂ©rifier si le prochain mot est un double
  • nextLine() : saisir la prochaine ligne de texte (jusqu’à un retour Ă  la ligne)
 il y a des nuances avec cette mĂ©thode que nous explorerons en dĂ©tail ci-dessous.

Objectifs d’apprentissage

À la fin de cette leçon vous devrez ĂȘtre en mesure de :

  • Savoir comment dĂ©clarer un Scanner pour la console et pour un String
  • Savoir utiliser les mĂ©thodes d’instance d’un Scanner pour obtenir le type de rĂ©ponse dĂ©sirĂ©.
  • Expliquer l’importance d’une invite de rĂ©ponse spĂ©cifique et claire avant l’instruction de saisie.
  • Expliquer c’est quoi un Locale et pourquoi il faut le spĂ©cifier si on veut saisir des valeurs dĂ©cimales.

CritĂšres de succĂšs

  • Je peux importer la classe Scanner, dĂ©clarer un Scanner pour la console et utiliser ses mĂ©thodes next, nextInt et nextDouble pour lire des donnĂ©es.
  • Je peux dĂ©finir un Locale appropriĂ© pour le Scanner si j’ai besoin de saisir des valeurs dĂ©cimales.
  • (enrichissement) Je peux valider les rĂ©ponses fournies par l’utilisateur avec les mĂ©thodes hasNextInt et hasNextDouble avant de tenter une conversion afin de rĂ©duire le nombre de plantages de mes programmes.

Structure gĂ©nĂ©rale d’un programme avec un Scanner

Les Scanner sont utilisĂ©s pour lire du texte Ă  partir de diffĂ©rentes sources. Pour commencer, on utilisera un Scanner qui surveille System.in pour complĂ©menter le PrintStream (System.out) qu’on utilise dĂ©jĂ  pour afficher des messsages texte Ă  la console. Bref, les Scanner vont nous permettre de lire des rĂ©ponses de l’utilisateur Ă  la console et d’avoir des programmes interactifs.

Si vous ne l’aviez pas devinĂ©, System.in et System.out sont les entrĂ©es et sorties standard de votre systĂšme d’exploitation, notamment la console.

La structure globale d’un programme qui utilise un Scanner est la suivante :

import java.util.*; // importer la définition de Scanner de java.util

void main() {
    Scanner console = new Scanner(System.in); // déclarer un Scanner pour la console

    // ... le reste du programme
}

Déclarer un Scanner

Le format de la dĂ©claration d’un Scanner est le suivant :

Scanner nom = new Scanner(source);

oĂč nom est le nom de la variable qui contiendra l’objet Scanner et source est la source de texte que le Scanner lira. Le nom est gĂ©nĂ©ralement un reflĂšt prĂ©cis de la source.

Pour lire de la console

On utilise System.in, l’entrĂ©e standard, comme source.

Scanner console = new Scanner(System.in);

Pour lire un String

On utilise un String comme source.

String text = "Bonjour, le monde!";
Scanner textReader = new Scanner(text);

Fermer un Scanner

On ne ferme jamais le Scanner pour la console parce qu’on s’en sert gĂ©nĂ©ralement jusqu’à la fin du programme interactif. Ce Scanner sera fermĂ© automatiquement en arrivant Ă  la fin de la mĂ©thode main.

Par contre, c’est important de fermer les Scanner pour toutes les autres sources de texte, comme un fichier ou un String. On ferme un Scanner avec la mĂ©thode close() une fois qu’on a finit de le lire. Par exemple :

textReader.close();

Introduction aux mĂ©thodes de Scanner - extraire les donnĂ©es d’un String

Pour comprendre comment les mĂ©thodes de Scanner fonctionnent, on va les tester sur diffĂ©rents String. Les sections plus bas montrent le Scanner dans le contexte d’un programme interactif.

La méthode next() : lire le prochain mot

La mĂ©thode next() saisit le prochain mot - plus spĂ©cifiquement, le prochain ‘jeton’ - dans le texte. Un jeton est une sĂ©quence de caractĂšres qui n’inclut pas d’espaces. Si la prochaine chose dans le texte commence par un ou plusieurs espaces, ces espaces seront ignorĂ©s en saisissant le jeton. La mĂ©thode next() retourne le jeton saisi.

String words = "\n   \tBonjour le monde!";
Scanner wordsReader = new Scanner(words); // Scanner qui utilise le texte 'words' comme source

String word; // variable pour stocker le mot lu

word = wordsReader.next(); // ignore les espaces initiaux puis saisit tout jusqu'au prochain espace, soit "Bonjour"
System.out.println(word);

word = wordsReader.next(); // saisit "le"
System.out.println(word); 

word = wordsReader.next(); // saisit "monde!"
System.out.println(word); 
wordsReader.close();

Les méthodes nextInt() et nextDouble() : convertir le texte en nombre

Peut ĂȘtre que la ligne de texte suivante reprĂ©sente des informations sur une personne, comme son Ăąge et sa moyenne scolaire. Connaissant le format du texte, on peut utiliser les mĂ©thodes appropriĂ©es pour lire les valeurs.

Les mĂ©thodes nextInt() et nextDouble() saisissent le prochain mot et tentent de le convertir en int ou double respectivement. Si le texte ne peut pas ĂȘtre converti en nombre, le programme plantera, alors il faut faire attention de :

  • bien aviser l’utilisateur du format attendu dans un programme interactif
  • bien observer les formats du texte dans des fichiers qu’on veut lire, comme un fichier qui contiendrait plusieurs lignes de donnĂ©es semblables Ă  l’exemple suivant.
String info = "Marie 15 85.5";
Scanner infoReader = new Scanner(info);
String nom = infoReader.next(); // saisir le nom
int age = infoReader.nextInt(); // saisir le texte pour le nombre entier
double moyenne = infoReader.nextDouble(); // saisir le nombre décimal
infoReader.close();
System.out.printf("%s a %d ans et sa moyenne est %.1f\n", nom, age, moyenne);

Si le programme fonctionne correctement, il nous donnera cette sortie :

Marie a 15 ans et sa moyenne est 85.5

Dans notre contexte spĂ©cifique - travailler en français avec des machines configurĂ©es en français - il y a quand mĂȘme un bon risque de plantage parce que le format pour le dĂ©cimal est diffĂ©rent sur un systĂšme anglais (.) que sur un systĂšme français (,). À l’interne, Java utilise toujours le . comme dĂ©cimal, mais il utilisera les formats du systĂšme dans ses Scanner pour interprĂ©ter les rĂ©ponses de l’utilisateur Ă  la console.

Donc c’est possible que Java prĂ©sume que le format 85,5 est le bon et lance une erreur quand il voit plutĂŽt 85.5. Ce n’est pas un bon systĂšme, mais il y a une façon de dire dans notre programme quel format on veut utiliser.

Spécifier le format des nombres décimaux

Quand on connaĂźt le format des nombres dĂ©cimaux dans le texte Ă  lire, ou on dit Ă  l’utilisateur quel format utiliser dans sa rĂ©ponse interactive, on devrait spĂ©cifier ce format explicitement dans le code.

On le fait en utilisant la classe Locale (aussi dans java.util) et les valeurs qu’elle dĂ©finit par dĂ©faut pour diffĂ©rents formats rĂ©gionaux. Dans notre contexte, on utilise l’une au l’autre des options suivantes :

  • Locale.CANADA : pour utiliser le . comme sĂ©parateur dĂ©cimal
  • Locale.CANADA_FRENCH : pour utiliser la , comme sĂ©parateur dĂ©cimal

Le code précédent devient alors :

String info = "Marie 15 85.5";
Scanner infoReader = new Scanner(info);

infoReader.useLocale(Locale.CANADA); // spécifie le format "."

String nom = infoReader.next(); 
int age = infoReader.nextInt(); 
double moyenne = infoReader.nextDouble(); 
infoReader.close();
System.out.printf("%s a %d ans et sa moyenne est %.1f\n", nom, age, moyenne);

Maintenant, le programme fonctionne correctement peu importe l’ordinateur utilisĂ© pour le lancer.

Version interactive : lire la console

En interagissant Ă  la console, c’est important de donner des invites de rĂ©ponse claires et spĂ©cifiques Ă  l’utilisateur afin qu’elle sache quoi taper et avec quel format, si nĂ©cessaire.

Voici un exemple en transformant le programme précédent en un programme interactif :

Scanner console = new Scanner(System.in); // source = entrée standard
console.useLocale(Locale.CANADA_FRENCH); // spécifie le format ","

System.out.print("Quel est votre prénom? "); // invite de réponse
String nom = console.next(); 

System.out.print("Quel est votre ùge? "); // invite de réponse
int age = console.nextInt(); 

// invite de réponse qui reflÚte la déclaration du Locale plus haut dans le code
System.out.print("Quelle est votre moyenne? (utilisez le ',' comme décimal) "); 
double moyenne = console.nextDouble(); 

System.out.printf("%s a %d ans et sa moyenne est %.1f\n", nom, age, moyenne);

// notez qu'on n'a pas fermé le Scanner pour la console

Enrichissement : valider la réponse avant de la saisir

Cette section est annotĂ©e comme “avancĂ©e” parce qu’elle incorpore des Ă©lĂ©ments de programmation que nous n’avons pas encore vus avec Java, notamment les opĂ©rations logiques et les boucles. Si vous ne comprenez pas tout de suite, ne vous inquiĂ©tez pas. Vous aurez l’occasion de revoir ces concepts plus tard dans le cours.

Si vous comprenez bien comment formuler une invite de rĂ©ponse prĂ©cise et comment assurer la cohĂ©rence entre votre invite et ce que vous avez Ă©crit dans votre code, peut-ĂȘtre que vous ne serez pas satisfait de laisser une erreur de frappe par l’utilisateur faire planter votre programme. C’est lĂ  qu’on peut commencer Ă  rendre le code plus tolĂ©rante aux erreurs en les gĂ©rant avant qu’elles ne causent des problĂšmes.

Pour valider une rĂ©ponse avant de la saisir, on utilise les mĂ©thodes hasNextInt() et hasNextDouble() pour vĂ©rifier si le prochain mot est convertible en int ou double respectivement. Si la rĂ©ponse est valide, on la saisit, la convertit et la conserve. Sinon, on doit vider le Scanner pour prĂ©parer la saisie suivante, alors on saisit la rĂ©ponse comme texte sans la conserver. On peut Ă©galement afficher un message d’erreur et inviter l’utilisateur Ă  rĂ©essayer.

Diagramme de flux pour valider une réponse

Scanner console = new Scanner(System.in);

System.out.print("Saisissez un nombre entier : ");
while (!console.hasNextInt()) {
    console.next(); // vider le Scanner du jeton incorrect
    System.out.println("Ce n'est pas un nombre entier valide.");
    System.out.print("Saisissez un nombre entier : ");
}

int number = console.nextInt();
System.out.println("Vous avez saisi " + number);

L’opĂ©rateur ! est l’inverse logique (“not”). Il transforme true en false et false en true. Dans ce contexte, !console.hasNextInt() signifie “tant que le Scanner n’a pas un nombre entier valide comme prochain jeton”.

Exercices

📚 Tester la comprĂ©hension

aucun quiz de vérification des concepts ici encore

đŸ› ïž Pratique

Travaillez dans le répertoire GitHub partagé par votre enseignant pour la pratique et les exercices.

  • Dupliquez tous les exemples dans le fichier Scanning.java.
  • Prenez une capture d’écran de votre Ă©diteur de code et du terminal pour les phases suivantes :
    • l’exemple “Bonjour le monde!” -> nommez l’image 4-5-Scanner1.png.
    • l’exemple “Marie 15 85.5” avec l’ajustement pour inclure le bon Local -> nommez l’image 4-5-Scanner2.png.
  • l’exemple interactif avec les invites de rĂ©ponse; rĂ©pondez comme vous le voulez -> nommez l’image 4-5-Scanner3.png.
  • l’exemple avec la validation de la rĂ©ponse; donnez au moins une mauvaise rĂ©ponse avant de donner une rĂ©ponse valide -> nommez l’image 4-5-Scanner4.png.

© 2022-2025 David Crowley