Menu

Vòng lặp while trong Java: cú pháp, do-while, lỗi hay gặp

Giải thích vòng lặp while trong Java: while kiểm tra điều kiện trước, do-while chạy ít nhất một lần, đọc đầu vào đến giá trị sentinel, break và continue, cách tránh vòng lặp vô hạn.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Khi bạn không có biến đếm

Vòng lặp for xoay quanh một biến đếm bạn khai báo từ đầu. Nhưng rất nhiều vòng lặp không có số lần rõ ràng: đọc từng dòng đến khi hết tệp, hỏi mật khẩu đến khi nhập đúng, chia đôi một số đến khi nó bằng 1. Với những trường hợp đó, vòng lặp while là lựa chọn tự nhiên nhất: nó chỉ đơn giản lặp lại chừng nào điều kiện còn đúng.

Vòng lặp (loop) while kiểm tra điều kiện trước mỗi lần lặp, kể cả lần đầu tiên. Nếu ngay từ đầu điều kiện đã sai, thân vòng lặp không chạy lần nào.

Điều kiện count > 0 được kiểm tra trước; nếu đúng, thân vòng lặp chạy; sau đó vòng lặp quay lại và kiểm tra tiếp. Dòng count-- là thứ cuối cùng làm điều kiện thành sai. Bỏ dòng đó đi, vòng lặp sẽ chạy mãi mãi.

Cấu tạo của vòng lặp while

Hãy so sánh với vòng lặp for ba phần mà bạn đã biết. Vòng lặp while tách ba việc đó ra: bạn khởi tạo trước vòng lặp, điều kiện nằm trong cặp ngoặc tròn, còn bước cập nhật nằm bên trong thân vòng lặp.

int i = 0;              // initialization - before the loop
while (i < 5) {         // condition - checked each pass
    System.out.println(i);
    i++;                // update - you must remember this yourself
}

Phần cuối chính là cái bẫy. Trong vòng lặp for, bước cập nhật nằm ngay cạnh điều kiện nên khó mà quên. Trong vòng lặp while, nó chỉ là một câu lệnh bình thường trong thân vòng lặp, và bug phổ biến nhất là quên viết nó khiến chương trình bị treo.

do-while: chạy thân vòng lặp ít nhất một lần

Đôi khi bạn cần thân vòng lặp chạy một lần trước rồi mới quyết định được có lặp lại hay không. Vòng lặp do-while kiểm tra điều kiện ở cuối, nên thân vòng lặp luôn được thực thi ít nhất một lần:

Bạn phải hỏi và đọc dữ liệu ít nhất một lần thì mới biết dữ liệu đó có hợp lệ hay không, và đó chính là điều do-while mang lại. Chú ý dấu chấm phẩy sau while (...): nó là bắt buộc, và quên nó là một lỗi biên dịch rất hay gặp.

Sự khác biệt so với while thông thường thấy rõ khi điều kiện sai ngay từ đầu:

Chỉ có do-while body được in ra. Vòng lặp while bỏ qua hoàn toàn thân của nó vì x < 5 đã sai trước lần kiểm tra đầu tiên.

Lặp đến giá trị sentinel

Một cách dùng kinh điển của while là đọc dữ liệu cho đến khi gặp một giá trị "dừng" đặc biệt, gọi là sentinel. Ở đây không có biến đếm nào; bạn cứ tiếp tục cho đến khi dữ liệu bảo bạn dừng:

Khuôn mẫu ở đây là đọc một lần trước vòng lặp, rồi đọc lại ở cuối mỗi lần lặp. Nhờ vậy điều kiện luôn kiểm tra dữ liệu mới. Nếu bạn quên lần đọc thứ hai trong thân vòng lặp, value không bao giờ thay đổi và bạn mắc kẹt trong vòng lặp vô hạn.

break và continue trong vòng lặp while

break và continue hoạt động giống hệt như trong vòng lặp for. break thoát khỏi vòng lặp ngay lập tức; continue nhảy thẳng về bước kiểm tra điều kiện, bỏ qua phần còn lại của lần lặp hiện tại:

Đoạn code này in ra 1 3 5 7 9. while (true) cố ý không bao giờ tự dừng, nên break là lối thoát duy nhất. Cẩn thận với continue trong vòng lặp while: vì bước cập nhật là một phần của thân vòng lặp, nhảy về đầu bằng continue trước khi bạn tăng biến đếm là một cách âm thầm làm treo vòng lặp. Trong ví dụ trên n++ chạy trước, nên an toàn.

Coi chừng vòng lặp vô hạn

Điều kiện cuối cùng phải trở thành sai, và việc đó hoàn toàn phụ thuộc vào thứ gì đó thay đổi bên trong thân vòng lặp. Hai thủ phạm quen thuộc là quên cập nhật và cập nhật sai cách:

int i = 0;
while (i < 5) {
    System.out.println(i);   // i never changes -> runs forever
}
int i = 0;
while (i != 10) {
    i += 3;   // 0, 3, 6, 9, 12... skips right past 10 -> runs forever
}

Ví dụ thứ nhất bị treo vì i không bao giờ được cập nhật. Ví dụ thứ hai bị treo vì biến đếm nhảy qua đúng giá trị mà điều kiện đang tìm, nên hãy ưu tiên < hoặc <= thay cho != khi bước nhảy có thể không rơi đúng vào giá trị đó. Một while (true) vẫn ổn nếu nó có một lệnh break chắc chắn chạy tới; còn nếu vô tình viết ra thì đó chỉ là bug.

Tiếp theo: vòng lặp for-each

Vòng lặp while là công cụ phù hợp khi bạn lặp đến khi một điều kiện thay đổi và không có số lần rõ ràng. Nhưng khi bạn chỉ muốn duyệt qua mọi phần tử của một mảng hay một list, không cần chỉ số, không cần quản lý điều kiện, thì có một cách gọn hơn nữa: vòng lặp for-each cải tiến. Đó là nội dung của trang tiếp theo.

Câu hỏi thường gặp

while và do-while trong Java khác nhau thế nào?

Vòng lặp while kiểm tra điều kiện trước lần lặp đầu tiên, nên thân vòng lặp có thể không chạy lần nào. Vòng lặp do-while chạy thân vòng lặp một lần trước, rồi mới kiểm tra điều kiện ở cuối, nên luôn chạy ít nhất một lần. Dùng do-while khi công việc phải làm xong rồi bạn mới quyết định có lặp lại hay không (ví dụ hỏi người dùng nhập dữ liệu, rồi kiểm tra dữ liệu đó).

Khi nào nên dùng vòng lặp while thay cho vòng lặp for trong Java?

Dùng vòng lặp while khi bạn không có biến đếm rõ ràng mà chỉ muốn lặp lại cho đến khi một điều kiện thay đổi: đọc đầu vào đến khi người dùng gõ quit, chờ đến khi một giá trị sẵn sàng, hoặc xử lý một hàng đợi đến khi nó rỗng. Chọn vòng lặp for khi bạn biết trước số lần lặp hoặc có sẵn một chỉ số để đếm.

Làm sao để dừng vòng lặp while vô hạn trong Java?

Bảo đảm có thứ gì đó trong thân vòng lặp cuối cùng làm điều kiện thành false (giảm biến đếm, dịch con trỏ, đổi một cờ). Với vòng lặp while (true) có chủ ý, đặt một lệnh break bên trong, được bảo vệ bằng một câu lệnh if. Nếu vòng lặp bị treo, nguyên nhân thường gặp nhất là quên cập nhật biến mà điều kiện phụ thuộc vào.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu