99 Ngày Java — Ngày 07: Vòng lặp for, while, do-while
Hôm qua code học rẽ nhánh; hôm nay nó học lặp lại — mảnh ghép thứ hai và cũng là mảnh cuối của điều khiển luồng. Ba anh em for, while, do-while mỗi người một việc, cộng thêm break/continue để lái dòng chảy, label cho vòng lặp lồng nhau — và ba cái bẫy khiến vòng lặp chạy sai hoặc… chạy mãi không dừng.

for — biết trước số lần lặp
Khi biết trước cần lặp bao nhiêu lần, for gói cả ba việc — khởi tạo, điều kiện, bước nhảy — vào một dòng:
// for: biết trước số lần lặpfor (int i = 1; i <= 5; i++) {
System.out.println("Lần chạy thứ " + i);
}
// ① int i = 1 — khởi tạo, chạy MỘT lần duy nhất// ② i <= 5 — kiểm tra TRƯỚC mỗi vòng; sai là thoát// ③ i++ — bước nhảy, chạy SAU thân vòng lặp// Thứ tự: ① → ② → thân → ③ → ② → thân → ③ → … → ② sai → thoátNhớ kỹ thứ tự: điều kiện được kiểm tra trước mỗi lần chạy thân, còn bước nhảy chạy sau. Biến i khai báo trong for chỉ sống trong vòng lặp — ra ngoài là hết phạm vi (đúng tinh thần phạm vi biến của Ngày 03). Với mảng và collection còn có for-each (for (int x : mang)) — gọn hơn hẳn khi chỉ cần duyệt qua từng phần tử; ta sẽ dùng nó dày đặc từ Ngày 08.
while & do-while — lặp theo điều kiện
Khi không biết trước số lần — đọc dữ liệu tới khi hết, chờ người dùng nhập đúng — while là lựa chọn tự nhiên. Khác biệt duy nhất giữa hai anh em: while kiểm tra trước (có thể không chạy lần nào), do-while kiểm tra sau (thân luôn chạy ít nhất một lần):
// while: lặp khi CHƯA biết trước số lần — kiểm tra trướcint soDu = 1000;
while (soDu >= 200) {
soDu -= 200; // rút 200 mỗi lần
}
System.out.println(soDu); // 0
// do-while: chạy thân ÍT NHẤT MỘT lần, kiểm tra sauint luaChon;
do {
luaChon = docLuaChonTuBanPhim(); // menu luôn hiện ít nhất 1 lần
} while (luaChon != 0);Mẹo chọn nhanh: menu, nhập liệu có xác nhận → do-while; mọi trường hợp "lặp khi còn…" khác → while; đếm số lần rõ ràng → for.
break & continue — lái dòng chảy giữa chừng
int[] mang = {4, 9, 7, 12, 5};
// break: tìm thấy là DỪNG cả vòng lặpfor (int x : mang) {
if (x > 10) {
System.out.println("Gặp " + x + " — dừng!");
break; // thoát hẳn vòng lặp
}
}
// continue: BỎ QUA phần còn lại của lần này, sang lần kếfor (int x : mang) {
if (x % 2 == 0) continue; // chẵn thì bỏ qua
System.out.println(x); // chỉ in số lẻ: 9 7 5
}break— thoát hẳn vòng lặp: tìm thấy rồi thì tìm tiếp làm gì.continue— bỏ qua lần này, nhảy sang lần kế: lọc phần tử không cần xử lý.Cả hai chính là guard clause phiên bản vòng lặp (Ngày 06): xử sớm trường hợp đặc biệt, thân vòng lặp nằm phẳng.
Vòng lặp lồng nhau & label
Duyệt bảng 2 chiều là gặp ngay vòng lặp lồng nhau: vòng ngoài chạy 1 lần thì vòng trong chạy trọn bộ số lần của nó. Vấn đề: break mặc định chỉ thoát vòng gần nhất. Muốn thoát cả cụm, đặt label trước vòng ngoài:
// Vòng lặp lồng nhau + label: break/continue nhắm vòng NGOÀI
tim: // nhãn đặt trước vòng ngoàifor (int hang = 1; hang <= 3; hang++) {
for (int cot = 1; cot <= 3; cot++) {
if (hang * cot == 6) {
System.out.println(hang + " x " + cot);
break tim; // thoát CẢ HAI vòng — không chỉ vòng trong
}
}
}
// Không có label, break chỉ thoát vòng TRONG — vòng ngoài vẫn chạy tiếpLabel hợp lệ nhưng hiếm khi nên lạm dụng — lồng sâu quá 2 tầng thường là dấu hiệu nên tách vòng trong thành method riêng (Ngày 10). Gặp label trong code cũ thì đọc hiểu được là đủ.
Ba cái bẫy kinh điển
// Bẫy 1: dấu chấm phẩy thừa — thân vòng lặp là câu lệnh RỖNGfor (int i = 0; i < 5; i++); // ← dấu ; này "nuốt" thân!
System.out.println("Chỉ in 1 lần");
// Bẫy 2: quên cập nhật biến điều khiển → lặp vô hạnint i = 0;
while (i < 5) {
System.out.println(i); // quên i++ → chạy mãi không dừng
}
// Bẫy 3: sửa điều kiện biên sai 1 đơn vị (off-by-one)for (int k = 0; k <= 5; k++) { } // chạy 6 lần, không phải 5!Bẫy 1 tàn khốc vì code vẫn compile — dấu ; ngay sau ) là một câu lệnh rỗng, thụt lề bên dưới chỉ đánh lừa mắt người (bài học quen thuộc từ Ngày 06). Bẫy 2 là vòng lặp vô hạn — treo chương trình, CPU 100%; trước khi viết while hãy tự hỏi "cái gì làm điều kiện này sai đi?". Bẫy 3 — off-by-one — là lỗi phổ biến nhất khi làm việc với mảng: < hay <= quyết định chạy 5 hay 6 lần, và Ngày 08 bạn sẽ thấy nó gây ArrayIndexOutOfBoundsException thế nào.
Bài tập nhỏ
In bảng cửu chương 7 bằng
for, rồi in cả 9 bảng bằng hai vòng lặp lồng nhau.Dùng
whiletính xem gửi 100 triệu lãi kép 6%/năm thì sau bao nhiêu năm vượt 200 triệu.Duyệt mảng
{3, 8, -2, 7, -5}: dùngcontinuebỏ qua số âm,breakdừng khi tổng vượt 15 — đoán kết quả trước khi chạy.Cố tình viết một vòng lặp vô hạn, quan sát rồi sửa — biết "mùi" của nó để sau này nhận ra ngay.
Kết luận
Điều khiển luồng đã đủ bộ: rẽ nhánh hôm qua, lặp hôm nay — for khi biết số lần, while/do-while khi lặp theo điều kiện, break/continue lái giữa chừng. Ngày 08 ta gặp người bạn đồng hành ăn ý nhất của vòng lặp: mảng (arrays) — nơi off-by-one hết chỗ trốn. Hẹn gặp lại!
Site Admin
Engineer and writer. Building things with TypeScript and distributed systems.
Bình luận (0)
Bạn cần đăng nhập bằng Google để bình luận.
Hãy là người bình luận đầu tiên.


