2009-11-25 12 views
10

Je suis en utilisant le code suivant:.Java: Boucle infinie à l'aide du scanner in.hasNextInt()

while (invalidInput) 
{ 
    // ask the user to specify a number to update the times by 
    System.out.print("Specify an integer between 0 and 5: "); 

    if (in.hasNextInt()) 
    { 
     // get the update value 
     updateValue = in.nextInt(); 

     // check to see if it was within range 
     if (updateValue >= 0 && updateValue <= 5) 
     { 
      invalidInput = false; 
     } 
     else 
     { 
      System.out.println("You have not entered a number between 0 and 5. Try again."); 
     } 
    } else 
    { 
     System.out.println("You have entered an invalid input. Try again."); 
    } 
} 

Cependant, si j'entre un 'w' il me dira: « Vous avez entré une entrée invalide Try Again " puis il va dans une boucle infinie montrant le texte "Spécifier un entier entre 0 et 5: Vous avez entré une entrée invalide.

Pourquoi cela se produit-il? N'est pas le programme censé attendre l'utilisateur d'entrer et appuyez sur Entrée à chaque fois qu'il atteint l'instruction:

if (in.hasNextInt()) 
+0

Puisque vous n'avez montré à personne ce qu'est 'in', ou comment vous l'avez construit, il n'y a pas de moyen de savoir comment il devrait se comporter! –

Répondre

13

Dans votre dernier bloc else, vous devez effacer le « w » ou autre entrée non valide du scanner. Vous pouvez le faire en appelant next() sur le scanner et en ignorant sa valeur de retour de jeter cette entrée invalide, comme suit:

else 
{ 
     System.out.println("You have entered an invalid input. Try again."); 
     in.next(); 
} 
2

variables indicatrices sont trop d'erreurs à utiliser. Utilisez le contrôle de boucle explicite avec des commentaires à la place. En outre, hasNextInt() ne bloque pas. C'est le contrôle non-bloquant pour voir si un appel next futur pourrait obtenir l'entrée sans bloquer. Si vous voulez bloquer, utilisez la méthode nextInt().

// Scanner that will read the integer 
final Scanner in = new Scanner(System.in); 
int inputInt; 
do { // Loop until we have correct input 
    System.out.print("Specify an integer between 0 and 5: "); 
    try { 
     inputInt = in.nextInt(); // Blocks for user input 
     if (inputInt >= 0 && inputInt <= 5) { 
      break; // Got valid input, stop looping 
     } else { 
      System.out.println("You have not entered a number between 0 and 5. Try again."); 
      continue; // restart loop, wrong number 
     } 
    } catch (final InputMismatchException e) { 
     System.out.println("You have entered an invalid input. Try again."); 
     in.next(); // discard non-int input 
     continue;  // restart loop, didn't get an integer input 
    } 
} while (true); 
+0

Y a-t-il une raison pour que le scanner soit définitif? – Tomek

+0

ce code produit toujours une boucle infinie – Tomek

+0

Je le rend final car il ne changera pas. Le compilateur pourrait faire certaines optimisations à cause de cela. C'est une bonne habitude de déclarer tout ce qui peut être définitif. La boucle sera rompue lorsque l'utilisateur entre une entrée correcte. C'est seulement infini si l'utilisateur choisit de le rendre infini. Si vous le souhaitez, je peux l'éditer afin qu'il ne permette qu'un nombre donné de tentatives. –

8

Le problème est que vous n'avez pas avancer la Scanner passé l'entrée problématique. De la documentation hasNextInt():

Retours true si le jeton suivant l'entrée de ce scanner peut être interprété comme une valeur int dans les radix par défaut en utilisant la méthode nextInt(). Le scanner n'avance aucune entrée.

Cela est vrai de toutes hasNextXXX() méthodes: ils reviennent true ou false, sans faire avancer le Scanner.

Voici un extrait pour illustrer le problème:

String input = "1 2 3 oops 4 5 6"; 
    Scanner sc = new Scanner(input); 
    while (sc.hasNext()) { 
     if (sc.hasNextInt()) { 
      int num = sc.nextInt(); 
      System.out.println("Got " + num); 
     } else { 
      System.out.println("int, please!"); 
      //sc.next(); // uncomment to fix! 
     } 
    } 

Vous constaterez que ce programme entrera dans une boucle infinie, demandant int, please! à plusieurs reprises.

Si vous ne commentez pas l'instruction sc.next(), le Scanner dépassera le jeton qui échoue hasNextInt(). Le programme serait alors imprimer:

Got 1 
Got 2 
Got 3 
int, please! 
Got 4 
Got 5 
Got 6 

Le fait qu'un échec hasNextXXX() vérification ne saute pas l'entrée est intentionnel: il vous permet si nécessaire d'effectuer des contrôles supplémentaires sur ce jeton. Voici un exemple pour illustrer:

String input = " 1 true foo 2 false bar 3 "; 
    Scanner sc = new Scanner(input); 
    while (sc.hasNext()) { 
     if (sc.hasNextInt()) { 
      System.out.println("(int) " + sc.nextInt()); 
     } else if (sc.hasNextBoolean()) { 
      System.out.println("(boolean) " + sc.nextBoolean()); 
     } else { 
      System.out.println(sc.next()); 
     } 
    } 

Si vous exécutez ce programme, il génèrerait les éléments suivants:

(int) 1 
(boolean) true 
foo 
(int) 2 
(boolean) false 
bar 
(int) 3 
3

Cette déclaration de Ben S.à propos de l'appel non bloquant est faux:

De plus, hasNextInt() ne bloque pas. C'est le contrôle non-bloquant pour voir si un prochain appel suivant pourrait avoir des entrées sans bloquer.

... même si je reconnais que le documentation peut facilement être mauvaise lecture de donner cet avis, et le nom lui-même implique qu'il doit être utilisé à cette fin. La citation pertinente, en mettant l'accent ajouté:

La prochaine() et les méthodes et leurs méthodes d'accompagnement de type primitif hasNext() (tels que nextInt() et hasNextInt()) première sauter une entrée qui correspond à la délimiteur, puis essayez de renvoyer le jeton suivant. Les hasNext et les méthodes suivantes peuvent bloquer l'attente d'autres entrées. Si une méthode hasNext est bloquée, elle n'a aucune connexion avec le fait que la méthode suivante associée bloque ou non.

C'est un point subtil, pour être sûr. Soit dire "Les deux les méthodes hasNext et suivantes", ou "Les deux hasnext() et next()" auraient impliqué que les méthodes d'accompagnement agiraient différemment. Mais vu qu'ils se conforment à la même convention de nommage (et à la documentation, bien sûr), il est raisonnable de s'attendre à ce qu'ils agissent de la même façon, et hasNext() dit clairement qu'il peut bloquer. Meta note: cela devrait probablement être un commentaire à la publication incorrecte, mais il semble que comme un nouvel utilisateur, je peux seulement poster cette réponse (ou modifier le wiki qui semble être préféré pour les changements sytlistic, pas ceux de substance).