Mục lục bài họcĐang ở d02-b2
← AP Computer Science A
0/16 bài đã học xong
Chương 2 · Unit 2 — Selection and Iteration · Bài 2/4 của chương · bài 6/16 của AP Computer Science A

Conditional Statements and Nested if

Câu lệnh điều kiện và if lồng nhau
← Mục lục bài học
Lý thuyết · English

if, else if, else

An if statement tests a boolean expression and runs its body only when the expression is true. Chaining with else if builds a decision ladder: Java tests the conditions in order and executes the body of the first one that is true, then skips every remaining branch. A final else runs when no condition matched.

Because the ladder stops at the first match, the conditions in a range ladder must be written from the most restrictive to the least restrictive. A ladder that starts with the widest test can never reach the branches below it, and the compiler reports nothing at all: the code is legal, it simply always answers the same way.

Nested conditionals

An if may appear inside the body of another if. The inner test is reached only when the outer test is true, so a nested pair expresses a logical and. In fact if (p) { if (q) { S } } and if (p && q) { S } behave identically. The two forms stop being interchangeable as soon as either level has an else: an else always belongs to the nearest unmatched if, no matter how the code is indented.

Giải thích tiếng Việt

Thang quyết định if / else if / else

Java xét các điều kiện theo thứ tự viết ra, chạy thân của nhánh đầu tiên đúng, rồi bỏ qua toàn bộ nhánh còn lại. Nhánh else cuối chỉ chạy khi không nhánh nào khớp.

Hệ quả trực tiếp: với một thang chia theo khoảng, điều kiện phải xếp từ chặt nhất tới lỏng nhất. Thang bắt đầu bằng điều kiện rộng thì mọi nhánh phía dưới trở nên không bao giờ với tới được — và trình biên dịch không hề báo gì, vì mã hoàn toàn hợp lệ. Nó chỉ luôn trả về cùng một câu trả lời. Đây là loại lỗi phải phát hiện bằng cách đọc thứ tự, không phải bằng cách chạy thử một lần.

Câu lệnh điều kiện lồng nhau

Một if đặt trong thân của if khác thì phép thử bên trong chỉ được chạm tới khi phép thử ngoài đúng — tức cặp lồng nhau diễn đạt phép và. Đúng vậy, if (p) { if (q) { S } } chạy y hệt if (p && q) { S }. Hai dạng chỉ khác nhau khi có else: else luôn thuộc về if gần nhất chưa có else, bất kể mã được thụt lề trông ra sao. Thụt lề chỉ đánh lừa mắt người, không đánh lừa trình biên dịch.

n % 15 == 0n % 3 == 0n % 5 == 0"FizzBuzz""Fizz""Buzz"else: ntruetruetruefalsefalsefalseĐảo hai ô trên cùng: nhánh "FizzBuzz" không bao giờ chạy, mà mã vẫn biên dịch.
Đọc hình theo mũi tên "false". Cột dọc bên trái là thứ tự Java xét điều kiện; mỗi mũi tên ngang là một nhánh đã chốt và thoát hẳn khỏi thang. Vì n % 15 == 0 là điều kiện chặt nhất nên nó phải nằm trên cùng. Nếu đặt n % 3 == 0 lên đầu thì mọi bội của 15 dừng ngay ở đó và trả về "Fizz" — nhánh "FizzBuzz" trở thành mã chết. Không có cảnh báo nào phát ra, chương trình chạy trơn tru và trả lời sai.
Ví dụ — nhánh không bao giờ chạy

Đoạn mã sau nhằm phân loại một số nguyên dương n: trả về 1 nếu chia hết cho 6, trả về 2 nếu chia hết cho 2, trả về 3 nếu chia hết cho 3, ngược lại trả về 4. Hãy chỉ ra nó sai ở đâu và sửa lại.

int r;
if (n % 2 == 0) {
    r = 2;
} else if (n % 3 == 0) {
    r = 3;
} else if (n % 6 == 0) {
    r = 1;
} else {
    r = 4;
}
Giải.

Tìm lỗi. Lấy n = 12, một bội của 6. Java xét điều kiện đầu tiên: 12 % 2 == 0 đúng, nên gán r = 2 rồi thoát khỏi cả thang. Nhánh n % 6 == 0 không bao giờ được chạm tới, vì mọi bội của 6 đều là số chẵn nên đã bị nhánh đầu bắt mất.

Vì sao trình biên dịch im lặng. Mã hợp lệ về cú pháp; "nhánh không bao giờ chạy" là lỗi logic, không phải lỗi cú pháp. Chỉ có đọc thứ tự mới thấy.

Sửa. Đưa điều kiện chặt nhất lên đầu:

int r;
if (n % 6 == 0) {
    r = 1;
} else if (n % 2 == 0) {
    r = 2;
} else if (n % 3 == 0) {
    r = 3;
} else {
    r = 4;
}

Bây giờ n = 12 cho 1, n = 8 cho 2, n = 9 cho 3, n = 7 cho 4 — đúng cả bốn nhóm.

Bẫy hay mất điểm — Lỗi đắt nhất của chương: xếp thang else if từ điều kiện rộng xuống điều kiện hẹp, khiến các nhánh dưới thành mã chết. Nó không sinh ra lỗi biên dịch, không sinh ra ngoại lệ, chỉ trả lời sai lặng lẽ. Cách chặn: trước khi viết thang, liệt kê một giá trị đại diện cho mỗi nhánh rồi lần tay từ trên xuống — nhánh nào không có giá trị nào rơi vào là nhánh chết, phải đẩy lên trên.
Phải nhớ — Thang else if dừng ở nhánh đúng đầu tiên, nên thứ tự là một phần của logic. Điều kiện chặt xếp trên. Và else luôn thuộc về if gần nhất chưa có else, không phải cái mà thụt lề gợi ý.

Đọc xong rồi — làm thử ngay

Bài tập của chương Unit 2 — Selection and Iteration gồm 14 câu trắc nghiệm và 8 đề tự luận. Đáp án hiện ngay khi chọn, miễn phí.

Làm bài tập chương →