Jak obsługiwać nieskończoną pętlę spowodowaną nieprawidłowym wejściem (InputMismatchException) za pomocą skanera

Więc utknąłem z tym kawałkiem kodu:

import java.util.InputMismatchException;
import java.util.Scanner;

public class ConsoleReader {

    Scanner reader;

    public ConsoleReader() {
        reader = new Scanner(System.in);
        //reader.useDelimiter(System.getProperty("line.separator"));
    }

    public int readInt(String msg) {
        int num = 0;
        boolean loop = true;

        while (loop) {
            try {
                System.out.println(msg);
                num = reader.nextInt();

                loop = false;
            } catch (InputMismatchException e) {
                System.out.println("Invalid value!");
            } 
        }
        return num;
    }
}

A oto moje wyjście:

Wstaw liczbę całkowitą:
Nieprawidłowa wartość!
Wstaw liczbę całkowitą:
Nieprawidłowa wartość!
...

Author: Pshemo, 2010-08-26

5 answers

Zgodnie z javadoc dla skanera:

Gdy skaner rzuca InputMismatchException, skaner nie przejdzie token, który spowodował wyjątek, tak aby mógł być pobrane lub pominięte przez inne metoda.

Oznacza to, że jeśli następny token nie jest int, rzuca InputMismatchException, ale token zostaje. Tak więc przy następnej iteracji pętli reader.nextInt() ponownie odczytuje ten sam token i ponownie rzuca wyjątek. Musisz użyć do góry. Dodaj reader.next() wewnątrz catch, aby zużyć token, który jest nieprawidłowy i musi zostać odrzucony.

...
} catch (InputMismatchException e) {
    System.out.println("Invalid value!");
    reader.next(); // this consumes the invalid token
} 
 48
Author: samitgaur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-26 05:27:09

To, co bym zrobił, to odczytanie całej linii za pomocą skanera.nextLine (). Następnie utwórz inny skaner, który odczytuje zwrócony ciąg znaków.

String line = reader.nextLine();
Scanner sc = new Scanner(line);

To sprawi, że Twoja przykładowa funkcja będzie wyglądać tak:

  public int readInt(String msg) {
        int num = 0;
        boolean loop = true;

        while (loop) {
            try {
                System.out.println(msg);
                String line = reader.nextLine();
                Scanner sc = new Scanner(line);
                num = sc.nextInt();   
                loop = false;
            } catch (InputMismatchException e) {
                System.out.println("Invalid value!");

            } 
        }
        return num;
    }

W ten sposób masz jeden skaner, który pobiera dane wejściowe i jeden, który je waliduje, więc nie musisz się martwić, że czytelnik będzie dbał o to, czy wprowadzi poprawną formę danych wejściowych.

 0
Author: cohensh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-26 05:29:08

Strażnikiem while-do jest zmienna 'loop'.

Sam wyjątek rzucony zanim twój kod dotrze do pętli przypisania = false; Aby być precyzyjnym, wyjątek jest wyrzucany w poprzednim poleceniu, które jest num = reader.nextInt ();

Po rzuceniu wyjątku, wartość zmiennej 'loop' jest 'true', ale twój kod przeskakuje, aby złapać blok, a następnie powtarza while-do. To while-do nigdy się nie skończy, ponieważ następna iteracja ponownie rzuci wyjątek, skoczy ponownie złapać blok i tak on

Aby zakończyć to while-do, musisz strzec swojego while-do z inną logiczną rzeczą, taką jak:

  1. wyjście, gdy czytelnik otrzyma znak nie-int
  2. Exit when EOF

Można to zrobić w bloku catch lub w innych liniach. Ale precyzyjne rozwiązanie zależy od twoich specyfikacji.

 0
Author: Hendra Jaya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-26 05:34:00

Możesz również spróbować tego:

   public int readInt(String msg) {
        int num = 0;
        try {
            System.out.println(msg);
            num = (new Scanner(System.in)).nextInt();
        } catch (InputMismatchException e) {
            System.out.println("Invalid value!");
            num = readInt(msg);
        } 
        return num;
    }
 0
Author: jerjer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-26 05:34:48
package nzt.nazakthul.app;

import java.util.*;

public class NztMainApp {

    public static void main(String[] args) {
    ReadNumber readObj = new ReadNumber();
    readObj.readNumber();
    }

}

class ReadNumber {
int no;

    int readNumber() {
    Scanner number = new Scanner(System.in);
    int no=0;
    boolean b=true;
    do {

        try {
            System.out.print("Enter a number:\t");
            no = number.nextInt();
        } catch (InputMismatchException e) {
            System.out.println("No Number");
            //e.printStackTrace();

            b=false;
        }

    }

    while (b);
    return no;

    }

}

Osobiście używam BufferedReader i InputStreamReader do odczytu String i sprawdzenia czy jest liczbą czy nie, ale ze skanerem jest mniej kodu. Kod jest zaznaczony i uruchom ok.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-23 09:50:16