首先,「無限迴圈=壞」並不正確!!
在遊戲的指令等待、伺服器的接收、UI的事件等待等場合,
有很多處理需要持續運行。
重要的是,安全停止的機制和運行方式的設計。
本文將總結如何以“安全的方式”使用 while(true)
的技巧,
以及 break
/ continue
/ 帶標籤的 break。
while (true) {
// 持續重複
}
使用旗標管理
boolean running = true;
while (running) {
String cmd = nextCommand(); // 等待輸入(阻塞)
if (cmd == null) break; // EOF 等等
if (cmd.isBlank()) continue; // 跳過空輸入
if (cmd.equals("quit")) running = false; // 下一輪退出
handle(cmd);
}
使用監視計數器作為保險
int guard = 10_000; // 防止過多迴圈
while (condition && guard-- > 0) {
// ...
}
guard 是「最多可以迴圈幾次」的上限。
guard-- > 0
的意思是「判斷當前 guard 是否大於 0,然後在判斷之後減 1」 (後置遞減)。
設置超時
long deadline = System.currentTimeMillis() + 5_000; // 最多 5 秒
while (!ready() && System.currentTimeMillis() < deadline) {
try {
Thread.sleep(50);
} catch (InterruptedException ignored) {}
}
if (!ready()) System.out.println("超時");
讓 CPU 休息(不進行自旋)
while (queue.isEmpty()) {
try {
Thread.sleep(10);
} catch (InterruptedException ignored) {}
}
// 或者使用阻塞 API
// Message msg = queue.take(); // 直到取出為止阻塞
import java.util.Scanner;
public class CommandLoop {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("> ");
String cmd = sc.nextLine().trim();
if (cmd.isEmpty()) continue; // 如果沒有輸入,則跳至下一個
if (cmd.equals("quit")) break; // 這裡退出
if (cmd.equals("heal")) heal();
else System.out.println("未知指令: " + cmd);
}
System.out.println("再見!");
}
static void heal() { System.out.println("皮卡丘已經恢復精力!"); }
}
重點:continue
是“跳過本輪剩餘部分”,break
是“跳出整個迴圈”。
Java 的標籤是 位於語句前的識別符 + 冒號 的形式。在搜尋類型的情況下特別方便。
int H = 10, W = 10;
int[][] cave = new int[H][W]; // 0: 通道, 1: 野生寶可夢
cave[4][7] = 1; // 隨機出現!
search: // ← 標籤
int y = 0;
while (y < H) {
int x = 0;
while (x < W) {
if (cave[y][x] == 1) {
System.out.println("發現! (" + y + "," + x + ")");
break search; // 整個雙重迴圈退出!
}
x++;
}
y++;
}
System.out.println("探索結束");
如果寫成 continue search;
,可以跳至外層的下一輪。
int i = 0;
while (i < party.size()) {
String name = party.get(i);
if (name == null || name.isBlank()) { i++; continue; } // 跳過無名
System.out.println(name + " 成為了首位!");
i++;
}
int j = 0;
while (j < events.size()) {
Event e = events.get(j);
if (e.type() == Event.Type.DEBUG) { j++; continue; } // 不顯示調試行
log(e);
j++;
}
下一次將探討 在實務中的 while 應用。包括輸入驗證/JDBC 的逐步獲取/狀態等待,
以及本次技巧應該如何應用!
皮卡丘!!
謝謝你閱讀到這裡。
即使之前覺得「程式設計很難…」,如果能讓你覺得「可能有點有趣…!」我會很高興。
期待你的下次來訪!
「這一章很容易理解!」
「這裡的表達沒有錯嗎?」
「希望下次可以做○○!」等等,
隨時歡迎留言告訴我!
原文出處:https://qiita.com/hitomin_poke/items/ad954cb433f21d425a70