使用 Scanner 做輸入校驗時,若輸入非整數,hasNextInt() 返回 false,但緩衝區內的非法 token 未被消費,導致死循環反覆進入 else 分支。本文深度解析根因並提供三種解決方案。
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("請輸入一個整數");
if (sc.hasNextInt()) {
int i = sc.nextInt();
System.out.println(i);
} else {
System.out.println("輸入錯誤,請重新輸入");
// 這裡缺少消費緩衝區非法 token 的操作!
}
}
hasNextInt() 只檢查下一個 token 是否為整數,不消費 tokenhasNextInt() 仍檢查 "abc",返回 falsewhile (true) {
Scanner sc = new Scanner(System.in); // 每次新建
if (sc.hasNextInt()) { ... }
else { System.out.println("錯誤"); }
}
next() 消費單個 token(適用單詞輸入)} else {
String next = sc.next(); // 消費掉 "abc"
System.out.println("您輸入的是:" + next + ",請重新輸入");
}
缺陷:輸入 "abc def 123" 會循環三次,分別消費 abc、def,最後處理 123。
nextLine() 消費整行(推薦,最徹底)} else {
String nextLine = sc.nextLine(); // 一次性消費整行 "abc def 123"
System.out.println(nextLine);
}
優勢:無論輸入多少非法字符,一次性清空緩衝區至換行符,下次循環直接檢查新輸入。
輸入: "22 aaa 333 ccc" 1. hasNextInt() -> true, nextInt() 消費 "22",緩衝區剩 "aaa 333 ccc" 2. hasNextInt() -> false, nextLine() 消費 "aaa 333 ccc",緩衝區空 3. 等待新輸入...
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("請輸入整數: ");
if (sc.hasNextInt()) {
int num = sc.nextInt();
System.out.println("您輸入: " + num);
break; // 或繼續業務邏輯
} else {
String garbage = sc.nextLine(); // 關鍵:消費整行非法輸入
System.out.println("無效輸入: [" + garbage + "],請重試");
}
}
sc.close();
理解緩衝區,就明白了!
hasNextXxx()只看不拿,nextXxx()拿走 token,nextLine()拿走整行。
異常分支必須消費掉非法數據,否則死循環必現。