Backend

99 Ngày Java — Ngày 82: Switch Expression và Pattern Matching

SSite Admin
17 tháng 10, 2026 3 phút đọc 7 lượt xem
99 Ngày Java — Ngày 82: Switch Expression và Pattern Matching

switch kiểu cũ là một câu lệnh dễ lỗi: quên break là rơi xuống nhánh dưới, và muốn lấy giá trị phải gán vào biến tạm. Java 14 chuẩn hóa switch expression; Java 21 hoàn thiện pattern matching cho switch và record pattern. Kết hợp lại, switch trở thành công cụ phân nhánh theo dạng dữ liệu, được compiler kiểm tra tính đầy đủ.

Switch Expression và Pattern Matching

1. Mũi tên: không fall-through, trả về giá trị

Với nhãn dạng case L ->, chỉ vế phải của nhãn khớp được chạy, không rơi xuống nhánh sau. Nhiều hằng dùng chung một nhánh thì ngăn bằng dấu phẩy. Khi switch được dùng như biểu thức, nó phải đầy đủ: mọi giá trị có thể có phải có nhánh. Với enum, liệt kê hết hằng thì không cần default, và thêm hằng mới sẽ làm compiler báo lỗi ở đúng chỗ cần sửa.

enum Status { NEW, PAID, SHIPPED, CANCELLED }

String label = switch (status) {
    case NEW, PAID -> "processing";
    case SHIPPED   -> "on the way";
    case CANCELLED -> "cancelled";
}; // no default: a new constant becomes a compile error

2. yield cho nhánh nhiều dòng

Khi một nhánh cần vài câu lệnh, viết khối trong ngoặc nhọn và dùng yield để trả giá trị của nhánh. yield chỉ thoát khỏi switch, còn return thoát khỏi phương thức; trong switch expression không được return. Nhãn kiểu cũ có dấu hai chấm vẫn dùng được trong switch expression, nhưng trộn hai kiểu nhãn trong cùng một switch là lỗi biên dịch.

int fee = switch (method) {
    case CARD -> 0;
    case BANK_TRANSFER -> {
        int base = amount > 1_000_000 ? 0 : 5_000;
        yield base + surcharge(region);
    }
    case CASH_ON_DELIVERY -> 15_000;
};

3. Pattern matching: phân nhánh theo kiểu

Trong Java 21, nhãn case có thể là type pattern: nếu giá trị khớp kiểu, nó được gán vào biến đã ép kiểu sẵn. Guard when thêm điều kiện cho pattern. Thứ tự có ý nghĩa: pattern rộng hơn đứng trước sẽ che pattern hẹp hơn và compiler từ chối. switch mặc định ném NullPointerException với null; thêm case null nếu null là dữ liệu hợp lệ.

String describe(Object value) {
    return switch (value) {
        case null -> "nothing";
        case Integer i when i > 100 -> "big number " + i;
        case Integer i -> "number " + i;
        case String s -> "text of length " + s.length();
        default -> value.getClass().getSimpleName();
    };
}

4. Record pattern: tách dữ liệu ngay tại nhãn

Record pattern, cũng ổn định từ Java 21, vừa kiểm tra kiểu vừa tách thành phần của record, kể cả lồng nhau. Kết hợp với sealed interface, compiler biết toàn bộ kiểu con nên switch không cần default. Hãy dành pattern matching cho dữ liệu dạng tổng hợp; hành vi gắn với kiểu vẫn nên là phương thức đa hình.

  • Ưu tiên switch không có default trên enum và kiểu sealed để compiler bắt thiếu nhánh.

  • Tránh guard dài; tách thành phương thức có tên.

sealed interface Shape permits Circle, Rect {}
record Circle(double radius) implements Shape {}
record Rect(double width, double height) implements Shape {}

double area(Shape shape) {
    return switch (shape) {
        case Circle(double r) -> Math.PI * r * r;
        case Rect(double w, double h) -> w * h;
    };
}

switch hiện đại vừa gọn vừa được kiểm tra đầy đủ lúc biên dịch. Ngày 83 nói kỹ về mảnh ghép làm nên điều đó: sealed classes.

Tài liệu đối chiếu

  • https://openjdk.org/jeps/361

  • https://openjdk.org/jeps/441

  • https://openjdk.org/jeps/440

S

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.

Bài viết liên quan

99 Ngày Spring — Ngày 82: Reactive Operators và Backpressure

map, flatMap, concatMap, zip, xử lý lỗi bằng onErrorResume và retryWhen, cùng khái niệm backpressure trong Reactor.

17 thg 10, 20263 phút6
99 Ngày Spring — Ngày 81: WebFlux nhập môn

Blocking so với non-blocking, Mono và Flux, luật không chặn event loop và khi nào reactive thật sự đáng dùng.

16 thg 10, 20263 phút4
99 Ngày Java — Ngày 81: var và Type Inference

var suy kiểu ở đâu, kiểu nào được chọn, những chỗ không dùng được và guideline để code vẫn dễ đọc.

16 thg 10, 20263 phút4