2

これの論理がわかりません。このコードを実行して文字 f などの非 int を入力すると、2 つの println を出力する無限ループに陥り、スキャナーに int を入力する機会がもう 1 つ与えられません。コンソールへの言葉。

public static void main(String[] args) {

    Scanner scan = new Scanner(System.in);//<<<<<SCANNER HERE
    int opponents = 0;
    boolean opponentsCreated = false;
    while(opponentsCreated == false)
    {
        try
        {
            System.out.print("How many players: ");
            int tempOpponents = scan.nextInt();
            if(tempOpponents > 0)
            {
                opponents = tempOpponents;
                opponentsCreated = true;
            }   
        }
        catch(InputMismatchException notAValidInt)
        {
            System.out.println("Not valid - must be a number greater than 0 ");
        }   
    }
}

しかし、単に Scanner を while ループ内で宣言するように変更すると、突然、プログラムが期待どおりに動作します。

public static void main(String[] args) {

    int opponents = 0;
    boolean opponentsCreated = false;
    while(opponentsCreated == false)
    {
        Scanner scan = new Scanner(System.in);//<<<<<SCANNER HERE
        try
        {
            System.out.print("How many players: ");
            int tempOpponents = scan.nextInt();
            if(tempOpponents > 0)
            {
                opponents = tempOpponents;
                opponentsCreated = true;
            }   
        }
        catch(InputMismatchException notAValidInt)
        {
            System.out.println("Not valid - must be a number greater than 0 ");
        }   
    }
}

正直なところ、私はここに 2 時間座って、自分のプログラムの何が問題なのかを突き止めようとしましたが、コードの両方のバージョンでスキャナーが範囲外ではなかったとしても、スキャナーを宣言した場所の問題であることがわかりました。では、なぜこのように機能するのか、非常に興味があります

4

2 に答える 2

1

@HovercraftFullOfEelsの回答に追加:

根本的な原因は、上記の例外の場合にスキャナーの位置が移動しないことです。したがって、スキャナーは同じ悪い入力を何度も繰り返します。JavaDoc の引用

変換が成功すると、スキャナは一致した入力を超えて進みます。

catch(InputMismatchException notAValidInt)
{
    scan.reset();
    System.out.println("Not valid - must be a number greater than 0 "); 
    //position is still 0
    scan.next(); //position is now 1
}

視覚化するには:

Input:                  f______________
Scanner position:       ^______________

InputMismatchException  ^______________
scan.next()             _^_____________ 

関連ソース(ソースコメントを見てください):

try {
            String s = next(integerPattern());
            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
                s = processIntegerToken(s);
            return Integer.parseInt(s, radix);
        } catch (NumberFormatException nfe) {
            position = matcher.start(); // don't skip bad token   
            throw new InputMismatchException(nfe.getMessage());
        }
于 2013-09-12T05:26:22.913 に答える