catchがwhileの外にあるのが原因です。例外が起これば何があろうと(対応する例外がある)catchに飛ぶため、whileから外れてしまいます。
ループを続けるためには、whileの中でcatchする必要があります。
ただし、今使っているtry-with-resourcesでcatchすると、catchする場合標準入力が閉じられてしまうため、別のtryを入れます。
java
1 int x = -1; // あらかじめwhileの継続条件を満たす値を入れておくと安全
2 do {
3 try {
4 System.out.print("0=true/1=false:");
5 x = stdIn.nextInt();
6 } catch (InputMismatchException e) {
7 System.out.println("不正な入力値です");
8 }
9 } while (x < 0 || x > 1);
10
無限ループの原因(コメントを受けて)
試してみると、
「0=true/1=false:不正な入力値です」の永久ループになってしまいました・・
自分でも試してみると、aなどの不正入力をすると無限ループ発生。
無限ループしないように工夫してスタックトレースを2回出してみるも、
Integer.parseInt()のNumberFormatExceprionと違って
Scanner#nextInt()のInputMismatchExceptionは入力が何かはスタックトレースに乗らないらしい
そこでScanner#nextIntの説明を読むとこんな文言が。
入力の次のトークンをintとしてスキャンします。次に示す方法で、次のトークンを有効なint値に変換できない場合、このメソッドはInputMismatchExceptionをスローします。変換に成功すると、スキャナは一致した入力の先に進みます。
この太字部分は、裏を返せば「変換できない場合スキャナの位置は動かない」ということではないか。
となるとどういうことが起こるか。例えば"a"を入れた場合、
- nextInt()で数値変換できないため例外発生。
- スキャナの位置は動かないため、まだ入力には"a"が残った状態になる。
- ループによりこの状態で再びnextInt()が呼ばれるため、また"a"を変換しようとして例外発生。
これが永遠に繰り返されるわけだ。
これを防ぐためには、例外発生時に変換できなかった文字を飛ばす必要がある。
java
1do {
2 try {
3 System.out.print("0=true/1=false:");
4 x = stdIn.nextInt();
5 } catch (InputMismatchException e) {
6 System.out.println("不正な入力値です");
7 stdIn.next(); // 変換できなかった文字列を飛ばす
8 }
9
10} while (x < 0 || x > 1);
ただこれだと不格好なので、nextInt()を使わず文字列で読み込んでparseInt()という方法も考えられる。
java
1do {
2 try {
3 System.out.print("0=true/1=false:");
4 x = Integer.parseInt(stdIn.next());
5 } catch (NumberFormatException e) {
6 System.out.println("不正な入力値です");
7 }
8
9} while (x < 0 || x > 1);
ちなみに
java
1 boolean a;
2 if (x == 0) {
3 a = true;
4 } else {
5 a = false;
6 }
ここのコードは次の1行で片づけられます。
java
1 boolean a = (x == 0);
2018/02/15 15:23
2018/02/15 15:55
2018/02/16 12:32