Je n'ai pas vraiment compris le comportement de Java Scanner et .nextLine ()

Le début de l'affaire

Écrivez du code comme celui-ci en Java

Main1.java


import java.util.*;

/**
 * Created 2017/05/23.
 */

public class Main1 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = sc.nextInt();
    for (int i = 0; i < num; i++) {
      String word = sc.nextLine();
      ary.add(word);
    }
    System.out.println(ary);
  }
}

Souvent dans les concours de programme 1: Recevez d'abord une entrée numérique Recevez plus d'entrées pour le nombre de fois entré 2: 1 Valeur d'entrée de 3: 2 de différentes manières Parce que j'avais besoin d'un programme comme ça Entrez le nombre de fois → Ecrivez la chaîne saisie sous forme de stockage dans ArrayList Cependant, le résultat de cette exécution est étrange

Valeur d'entrée
2
a
b (impossible d'entrer)

Résultat d'exécution
[, a]

Un blanc mystérieux? J'étais dans une situation où j'étais, alors j'ai décidé d'enquêter sur la cause ...

Tout d'abord, pour comprendre les spécifications de .nextLine ()

Tout d'abord, saisissons les spécifications avec la référence https://docs.oracle.com/javase/jp/8/docs/api/java/util/Scanner.html#nextLine--

nextLine

public String nextLine() Fait avancer le scanner jusqu'à la ligne actuelle et renvoie l'entrée ignorée. Cette méthode renvoie le reste de la ligne actuelle, à l'exclusion du dernier saut de ligne. La position est définie au début de la ligne suivante. Cette méthode continue de rechercher des sauts de ligne dans l'entrée, donc si le saut de ligne n'existe pas, elle peut mettre en mémoire tampon toutes les entrées qui recherchent des lignes à sauter. Valeur de retour: Lignes sautées exception: NoSuchElementException-si la ligne est introuvable IllegalStateException-si ce scanner est fermé


~~ Ouais, je ne sais pas de quoi tu parles ~~ À la suite de diverses enquêtes pour le moment -.NextLine () lit également les blancs (lignes vides) J'ai compris ça Mais cette fois, je me pose la question de savoir d'où viennent les blancs (lignes vides).

Examinez le comportement réel un par un

Vérifier en écrivant le code source tout en vérifiant (il est beaucoup plus rapide de bouger sa main que de se soucier de sa tête) L'ordre des noms de fichiers dans le code source est dans le désordre, mais pensez qu'il s'agit du résultat de divers essais. ~~ Je ne peux pas lire ceci avec juste la référence ... ~~

Tout d'abord, examinons rapidement le comportement de Scanner et .nextLine ().

Comportement de Scanner et .nextLine ()

Main5

Main5.java


import java.util.Scanner;

/**
 * Created 2017/05/25.
 *Le comportement de nextLine
 */
public class Main5 {
   public static void main(String[] args) {
      String word = "123 test";
      Scanner sc = new Scanner(word);
      String line = sc.nextLine();

      System.out.println(word);
      //Résultat d'exécution:123 test
      System.out.println(line);
      //Résultat d'exécution:123 test
   
   }
}
Résultat d'exécution
123 test
123 test

C'est très facile à comprendre

Main6 Ensuite, je vais essayer plusieurs analyses

Main6.java


import java.util.Scanner;

/**
 * Created 2017/05/25.
 */
public class Main6 {
  public static void main(String[] args){
    String word = "123 test";
    Scanner sc = new Scanner(word);
    int num     = sc.nextInt(); 
    String line = sc.nextLine();

    System.out.println(word);
    //Résultat d'exécution:123test

    System.out.println(num);
    //Résultat d'exécution: 123
    
    System.out.println(line);
    //Résultat d'exécution: test

  }
}

Résultat d'exécution
123 test
123
 test

Ce à quoi je veux faire attention ici, c'est le résultat de sortie de la ligne. Si vous faites .nextLine (); après avoir fait .nextInt (); à l'avance, la partie numérique a déjà été lue. Vous pouvez voir que seul le test vierge + reste

Alors que faire si vous faites .nextLine () après avoir tout lu? Essayons!

Main7

Main7.java


import java.util.Scanner;

/**
 * Created 2017/05/25.
 */
public class Main7 {
  public static void main(String[] args){
    String word = "123 test";
    Scanner sc = new Scanner(word);
    int num     = sc.nextInt();
    String word2 = sc.next();
    
    //String line = sc.nextLine();
    //J'obtiens une erreur correctement
    //Exception in thread "main" java.util.NoSuchElementException: No line found

    System.out.println(word);
    //Résultat d'exécution:123test

    System.out.println(num);
    //Résultat d'exécution: 123

    System.out.println(word2);
    //Résultat d'exécution:test

    //System.out.println(line);
    //Résultat d'exécution:Non exécuté en premier lieu en raison de l'erreur ci-dessus

  }
}
Résultat d'exécution 1
123 test
123
test

Bien qu'il soit écrit dans le commentaire, si vous décommentez .nextLine () et que vous l'exécutez, une erreur se produira.

Résultat d'exécution 2(.nextLine();Décommenter et exécuter)
Exception in thread "main" java.util.NoSuchElementException: No line found
	at java.util.Scanner.nextLine(Scanner.java:1540)
	at Java.Nexts.Main7.main(Main7.java:15)

Cela ne révèle pas la vérité ... Il renverra une erreur comme "Il n'y a pas de ligne!" Cependant, si vous en ajoutez un peu, l'erreur disparaîtra.

Main8

Main8.java


import java.util.Scanner;

/**
 * Created 2017/05/25.
 */
public class Main8 {
  public static void main(String[] args){
    String word = "123 test\n";
    Scanner sc = new Scanner(word);
    int num     = sc.nextInt();

    String word2 = sc.next();

    String line = sc.nextLine();
  
    System.out.println(word);//
    //Résultat d'exécution:123test
    //
    //Il y a un espace (ligne de rupture) en haut
    
    System.out.println(num);
    //Résultat d'exécution: 123

    System.out.println(word2);
    //Résultat d'exécution:test

    System.out.println(line);
    //Résultat d'exécution: (Vide)
    //Il est vide, mais il lit en fait une ligne vide, donc cela ne signifie pas que la ligne n'existe pas → cela ne génère pas d'erreur!
    //Système ici.out.println(line);C'est très facile à comprendre si vous l'exécutez avec le débogage attaché!

  }
}
Résultat d'exécution
123 test

123
test

Oui c'est la vérité Ajoutez le code de saut de ligne "\ n" au mot chaîne. Ensuite, après la numérisation jusqu'à word2, contrairement à Main7, les sauts de ligne resteront. String line = sc.nextLine (); se lit comme un saut de ligne (ligne vide) En conséquence, la ligne contiendra des caractères vides.

Cela peut être vu visuellement en utilisant la fonction de débogage de l'EDI. nextline.png Vous pouvez voir qu'il y a un "" dans la ligne

Alors qu'est-ce qui se passait

Maintenant, vous pouvez enfin voir si le code Main1 s'est comporté étrangement 1: Tout d'abord, lors de la saisie d'une valeur numérique, après avoir appuyé sur 2 et appuyé sur Entrée, "2 \ n" est entré dans le contenu sc. 2: Lors de la numérisation avec int num = sc.nextInt ();, num = 2 est stocké et le contenu de sc est uniquement "\ n" 3: Après le démarrage de la boucle, String word = sc.nextLine (); lit le contenu sc restant actuel "\ n" Stocker dans une aire en tant que personnage vide 4: Le contenu de sc est vide, alors lisez et stockez la nouvelle entrée "a" ici. 5: À ce stade, la boucle s'arrête car le processus est effectué deux fois. 6: Le contenu de ary devient [, a]

En conclusion -Scanner renvoie la valeur de l'emplacement actuel (la partie où le contenu reste) -.NextLine () lit également les lignes vides C'était un problème qui se produisait dans la technique combinée de

Alors, comment obtenez-vous le mouvement idéal?

La solution fondamentale est de créer deux scanners De cette façon, vous n'aurez pas à lire l'épave lors de la saisie des chiffres.

Main4.java


import java.util.ArrayList;
import java.util.Scanner;

/**
 * Created 2017/05/25.
 *Sentir que la cause était enfin comprise
 */
public class Main4 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    Scanner sc2 = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = sc.nextInt();
    for (int i = 0; i < num; i++) {
      String word = sc2.nextLine();
      ary.add(word);
    }
    System.out.println(ary);
  }
contribution
2
a
b
Résultat d'exécution
[a, b]

C'est parfait!

De plus, si vous savez que la chaîne que vous entrez n'est pas séparée par des espaces Vous pouvez obtenir le même résultat simplement en utilisant .next ()

Main2.java


import java.util.*;

/**
 * Created 2017/05/23.
 */
public class Main2 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = sc.nextInt();
    for (int i = 0; i < num; i++) {
      String word = sc.next();
      ary.add(word);
    }
    System.out.println(ary);
  }
}
contribution
2
a
b
Résultat d'exécution
[a, b]

Cependant, sachez que le code Main2 peut se comporter involontairement lorsque vous tapez une phrase séparée par des blancs.

2
a b c
Résultat d'exécution
[a, b]

2017/5/25 postscript J'ai une solution plus intelligente dans les commentaires

Main9.java


import java.util.ArrayList;
import java.util.Scanner;

/**
 * Created 2017/05/25.
 *Demandez à Qiita de vous enseigner une manière plus intelligente
 */
public class Main9 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = Integer.parseInt(sc.nextLine());    //Integer.Une fois converti en nombre complet à l'aide de parseInt, il peut être lu par nextLine!
    for (int i = 0; i < num; i++) {
      String word = sc.nextLine();
      ary.add(word);
    }
    System.out.println(ary);
  }
}
contribution
2
a
b
Résultat d'exécution
[a, b]

Tout d'abord, .nextLine () traite le résultat de la lecture comme un type String. pour cette raison int num = sc.nextLine(); Si vous écrivez tel quel ʻError: (13, 26) java: Type incompatible: Impossible de convertir java.lang.String en int: Et type incohérence, et ne peut pas être stocké dans int num pourtantint num = Integer.parseInt(sc.nextLine()); En écrivant, la valeur lue par.nextLine () peut être convertie en valeur numérique, donc elle peut être stockée dans ʻint num! Cette façon d'écrire ne nécessite pas plusieurs scanners De plus, c'est comme appeler .nextLine () pour chaque ligne saisie, ce qui rend le code très facile à comprendre.

Impressions

~~ Java est gênant ~~ Plaisanter de côté Je veux entrer → Scanner sc = new Scanner (System.in); Je veux lire ligne par ligne → .nextLine (); Il est indéniable qu'il y avait une idée semblable à une copie que vous devriez utiliser. Cette fois, j'ai bien compris que j'avais une compréhension essentielle du Scanner. Il y a encore beaucoup de choses que je ne comprends pas à propos de Java, alors j'aimerais continuer à étudier dur.

2018/01/19 Quand je l'ai relu après un long moment, je m'inquiétais à ce sujet, alors j'ai corrigé un Vous n'avez pas à créer un nouveau scanner, scannez simplement les blancs une fois et cela fonctionnera très bien.

ScanSample.java


import java.util.ArrayList;
import java.util.Scanner;

/**
 * Created 2018/01/19.
 *correction
 */
public class ScanSample {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    ArrayList<String> ary = new ArrayList<String>();
    int num = sc.nextInt();
    String blank = sc.nextLine();
    for (int i = 0; i < num; i++) {
      String word = sc.nextLine();
      ary.add(word);
    }
    System.out.println(ary);
  }
}
contribution
2
a
b
Résultat d'exécution
[a, b]

Recommended Posts

Je n'ai pas vraiment compris le comportement de Java Scanner et .nextLine ()
J'ai comparé les caractéristiques de Java et .NET
À propos de next () et nextLine () de la classe Scanner
J'ai résumé les types et les bases des exceptions Java
J'ai essayé de résumer les bases de kotlin et java
Les débutants en Java ont brièvement résumé le comportement de Array et ArrayList
[Java] J'ai réfléchi aux mérites et aux utilisations de "interface"
J'ai essayé de résumer les méthodes de Java String et StringBuilder
À propos du fonctionnement de next () et nextLine ()
[jour: 5] J'ai résumé les bases de Java
[Java] [Spring] Tester le comportement de l'enregistreur
J'ai essayé de traduire la grammaire de R et Java [Mis à jour de temps en temps]
[Java] Comprendre la différence entre List et Set
En vérifiant le fonctionnement de Java sous Linux, j'ai pu comprendre la compilation et la hiérarchie.
Différence entre next () et nextLine () dans Java Scanner
[Java] La partie déroutante de String et StringBuilder
Essayez Progate Free Edition [Java I]
J'ai reçu les données du voyage (application agenda) en Java et j'ai essayé de les visualiser # 001
Résumé du comportement de ToString avec les annotations Java et Groovy
Veuillez noter la division (division) de java kotlin Int et Int
La comparaison d'énumération est ==, et equals est bonne [Java]
[Pour les débutants] Comprendre rapidement les bases de Java 8 lambda
Organiser l'état actuel de Java et envisager l'avenir
Langage Java du point de vue de Kotlin et C #
Vérifiez le comportement de Java Intrinsic Locks avec bpftrace
Classes et instances Java comprises dans la figure
[Note] Sortie Java de la somme des éléments pairs et impairs
Commande pour vérifier le nombre et l'état des threads Java
Comprendre le modèle Singleton en comparant le code Java et JavaScript
Que dois-je faire après janvier 2019 concernant le problème du paiement Java et le problème de la fin du support Java 8?
J'ai essayé JAX-RS et pris note de la procédure
[Java] J'ai essayé d'implémenter la combinaison.
Avantages et inconvénients de Java
Je ne suis pas sûr du traitement parallèle Java
Comprendre le modèle Iterator en comparant le code Java et JavaScript
J'ai étudié le constructeur (java)
[Vue Action :: Modèle manquant] Je n'ai pas compris la signification de l'instruction d'erreur, alors je l'ai recherchée.
Je n'ai pas compris la signification de DI, @Autowired ou injection, alors j'ai recherché.
[Java] Divers résumés joints aux chefs de classe et aux membres
[Java] Obtenez les dates des derniers lundi et dimanche dans l'ordre
Je veux comprendre le flux des paramètres de demande de traitement Spring
L'histoire de ne pas connaître le comportement de String en passant par Java
Je veux revenir à l'écran précédent avec kotlin et java!
J'ai essayé le type d'entrée / sortie de Java Lambda ~ Map edition ~
Lire les 4 premiers octets du fichier de classe Java et générer CAFEBABE
De Java naissant (3 ans) à Node.js (4 ans). Et l'impression de retourner à Java
Depuis que j'ai réussi l'Oracle Java Bronze, j'ai résumé les grandes lignes du test.
Le comportement de JS fonctionnant sur `Java SE 8 Nashorn` a soudainement changé
À propos du comportement de ruby Hash # ==
[Java] Supprimer les éléments de la liste
J'ai comparé les constructeurs PHP et Java
Comprendre le mécanisme de base de log4j2.xml
[java8] Pour comprendre l'API Stream
À propos de Biocontainers fastqc et Java
[Édition Java] Histoire de la sérialisation