Menu

Câu lệnh switch trong Java: case, fall-through và cú pháp mũi tên

Giải thích câu lệnh switch trong Java: nhãn case, break và fall-through, nhánh default, gom nhóm case, dạng mũi tên hiện đại và biểu thức switch.

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.

switch dùng để làm gì

Câu lệnh switch so sánh một giá trị với danh sách các lựa chọn cố định và chạy nhánh khớp. Khi bạn thấy mình viết một chuỗi if/else if dài cứ kiểm tra cùng một biến với các hằng số khác nhau, switch diễn đạt điều đó rõ ràng hơn.

Nó chỉ so sánh bằng với các hằng số lúc biên dịch: nó không kiểm tra được khoảng giá trị hay kết hợp điều kiện. Với những trường hợp đó, hãy dùng if/else.

Câu lệnh switch cổ điển

Dạng truyền thống dùng nhãn case với dấu hai chấm và một break sau mỗi nhánh:

Java tính giá trị day, nhảy tới case khớp, chạy các câu lệnh của nó, và break thoát khỏi switch. Nhánh default chạy khi không có gì khác khớp, hãy coi nó như else. Nó không bắt buộc, nhưng có nó là thói quen tốt để các giá trị bất ngờ không lặng lẽ lọt qua.

Bẫy break: fall-through

Đây là bug switch phổ biến nhất. Nếu bạn bỏ sót break, chương trình không dừng ở cuối case đã khớp mà rơi xuống (fall through) case tiếp theo và tiếp tục chạy cho đến khi gặp break hoặc dấu ngoặc đóng:

Bạn có thể nghĩ chỉ in ra Level 1, nhưng đoạn này in cả ba dòng. Vì case 1 không có break, luồng điều khiển trượt thẳng vào case 2 và case 3. Luôn thêm break trừ khi bạn thật sự muốn fall-through, và khi bạn cố ý dựa vào nó, hãy để lại một chú thích để người đọc sau biết đó là có chủ đích.

Gom nhóm các case

Fall-through có một cách dùng chính đáng và gọn gàng: xếp chồng các nhãn case để nhiều giá trị dùng chung một khối lệnh. Đặt các nhãn liền nhau, không có code ở giữa:

Ở đây 'A', 'B' và 'C' đều chạy cùng dòng "Pass". Đây là cách đúng để nói "bất kỳ giá trị nào trong số này đều làm cùng một việc".

switch với chuỗi

Bạn không bị giới hạn ở số. Từ Java 7 bạn có thể switch trên một String, rất hợp cho lựa chọn menu hay tên lệnh:

So khớp phân biệt chữ hoa chữ thường: "Stop" sẽ không khớp với "stop", nên hãy chuẩn hóa trước (ví dụ command.toLowerCase()) nếu cách viết hoa của đầu vào không cố định. Một bẫy nữa: nếu command là null, switch sẽ ném ra NullPointerException, vì vậy hãy kiểm tra null trước khi tới đó.

Cú pháp mũi tên hiện đại

Java mới hơn (14+) thêm dạng mũi tên, case label -> ..., loại bỏ bẫy fall-through ngay từ thiết kế. Mỗi case mũi tên chạy đúng một nhánh và không bao giờ rơi xuống, nên không có break nào để quên:

Để ý rằng bạn gom nhóm giá trị bằng dấu phẩy (case 6, 7) thay vì xếp chồng nhãn, và không hề có một break nào. Với nhiều câu lệnh, dùng một khối: case 1 -> { ...; ... }. Hãy ưu tiên dạng này trong code mới: nó ngắn hơn và loại bỏ cả một nhóm bug.

switch dưới dạng biểu thức

Dạng mũi tên còn có thể tạo ra một giá trị. Biểu thức switch trả về kết quả mà bạn có thể gán thẳng vào một biến, không cần biến tạm, không cần lặp lại phép gán ở mọi nhánh:

Toàn bộ switch (...) { ... } được tính thành một số và lưu vào days. Chú ý dấu chấm phẩy sau dấu ngoặc đóng: nó là một phần của câu lệnh gán. Biểu thức switch phải bao quát hết (exhaustive), tức xử lý mọi giá trị có thể, đó là lý do có default ở đây; và để ý rằng một nhánh không khớp có thể ném ra ngoại lệ thay vì trả về giá trị. Nếu một nhánh cần nhiều câu lệnh trước khi trả về giá trị, hãy dùng một khối với yield:

case 2 -> {
    boolean leap = (year % 4 == 0);
    yield leap ? 29 : 28;
}

yield là cách một khối mũi tên trả lại giá trị của nó, tương đương với break mang theo kết quả trong thế giới biểu thức.

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

switch chọn một nhánh trong nhiều nhánh; đôi khi bạn lại cần lặp một khối lệnh nhiều lần. Vòng lặp for chạy code một số lần có kiểm soát, đếm qua một khoảng hoặc đi qua từng phần tử, và đó là nội dung của trang tiếp theo.

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

Khi nào nên dùng switch thay cho if-else trong Java?

Dùng switch khi bạn so sánh một giá trị với nhiều lựa chọn cố định, là hằng số, như số thứ tự ngày, một lựa chọn trong menu hay một enum. Nó dễ đọc hơn một chuỗi if/else if dài và thể hiện rõ ý "chọn một nhánh trong các giá trị đã biết này". Hãy giữ if/else khi điều kiện liên quan đến khoảng giá trị (x > 10), nhiều biến, hoặc bất cứ thứ gì không phải phép so sánh bằng đơn giản với một hằng số.

Vì sao cần break trong câu lệnh switch của Java?

Với cú pháp dấu hai chấm cổ điển, khi một case khớp, chương trình rơi xuống (fall through) các case tiếp theo cho đến khi gặp break hoặc hết switch. break chặn điều đó lại. Quên nó là một bug kinh điển: bạn khớp case 1: và vô tình chạy luôn code của case 2:, case 3:, v.v. Cú pháp mũi tên mới hơn (case 1 -> ...) không bao giờ rơi xuống, nên bạn hoàn toàn không cần viết break.

Câu lệnh switch trong Java có dùng được với String không?

Có. Từ Java 7 bạn có thể switch trên một String, và cũng có thể switch trên int, char, byte, short, các kiểu wrapper của chúng và các giá trị enum. Bạn không thể switch trên long, double, float hay boolean. So khớp chuỗi phân biệt chữ hoa chữ thường, nên "Yes" và "yes" là hai case khác nhau.

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