CodeGym /Các khóa học /JAVA 25 SELF /Pattern Matching for instanceof

Pattern Matching for instanceof

JAVA 25 SELF
Mức độ , Bài học
Có sẵn

1. Vấn đề của instanceof kiểu cổ điển

Hãy bắt đầu với một chút hoài niệm. Trước Java 16, khi bạn cần kiểm tra kiểu của đối tượng rồi sử dụng nó như kiểu đó, bạn phải viết một mẫu dài dòng với kiểm tra instanceof và ép kiểu tường minh:

Object obj = ...; // một đối tượng nào đó

if (obj instanceof String) {
    String s = (String) obj;
    System.out.println("Độ dài chuỗi: " + s.length());
}

Nhàm chán nhưng thường gặp

Mẫu này xuất hiện rất thường xuyên — bộ xử lý sự kiện, làm việc với các collection không đồng nhất, business logic với kế thừa, v.v.

Vì sao bất tiện

  • Lặp mã — phải ghi kiểu hai lần: cả trong instanceof và trong ép kiểu.
  • Nguy cơ lỗi — dễ vô tình ép về sai kiểu và nhận ClassCastException.
  • Mã “ồn ào” — giảm tính dễ đọc, đặc biệt khi có nhiều kiểm tra.

2. Pattern Matching cho instanceof: Cú pháp mới

Trong Java 16 đã thêm pattern matching cho instanceof. Giờ bạn kiểm tra kiểu và đồng thời khai báo biến đúng kiểu, biến này chỉ khả dụng bên trong nhánh if.

Cú pháp mới

if (obj instanceof String s) {
    // s đã là String!
    System.out.println("Độ dài chuỗi: " + s.length());
}
  • Sau kiểu trong instanceof ghi tên biến mới: String s.
  • Biến chỉ khả dụng bên trong khối nơi điều kiện đúng.
  • Không cần viết ép kiểu (String) — trình biên dịch đảm bảo tất cả.

Điều kỳ diệu là gì? Trình biên dịch kiểm tra kiểu và, nếu phù hợp, “mở” biến với kiểu cần thiết. Nếu không, khối đơn giản là không được thực thi.

Trông như thế nào trong mã thực tế

Object obj = "Xin chào, Java 16+!";

if (obj instanceof String s) {
    System.out.println("Chữ hoa: " + s.toUpperCase());
} else {
    System.out.println("Không phải chuỗi!");
}

3. An toàn và dễ đọc: vì sao điều này tuyệt

Loại bỏ lỗi ClassCastException

Object obj = 123;
// String s = (String) obj; // Bùm! Ngoại lệ.

Với pattern matching, biến chỉ được tạo khi kiểm tra kiểu thành công — không có ép kiểu “sai”.

Mã ngắn gọn và dễ hiểu hơn
Hai dòng thành một. Ít mã “ồn ào” hơn — dễ đọc và bảo trì.

Ví dụ: xử lý nhiều kiểu

public static void printInfo(Object obj) {
    if (obj instanceof String s) {
        System.out.println("Chuỗi có độ dài " + s.length());
    } else if (obj instanceof Integer i) {
        System.out.println("Số nguyên: " + (i + 1));
    } else {
        System.out.println("Kiểu không xác định: " + obj);
    }
}

4. Ví dụ sử dụng và các lưu ý

Kiểm tra nhiều kiểu

Object value = ...;

if (value instanceof String s) {
    System.out.println("Đây là chuỗi: " + s);
} else if (value instanceof Number n) {
    System.out.println("Đây là số: " + n);
} else {
    System.out.println("Thứ gì đó khác: " + value);
}

Sử dụng với null
Nếu đối tượng bằng null, thì instanceof luôn trả về false — sẽ không có NPE, nhưng khối sẽ không chạy.

Object obj = null;

if (obj instanceof String s) {
    // Khối này KHÔNG BAO GIỜ chạy nếu obj == null
    System.out.println("Chuỗi: " + s);
} else {
    System.out.println("obj là null hoặc không phải chuỗi");
}

Pattern matching với kế thừa

class Animal {}
class Dog extends Animal {
    void bark() { System.out.println("Gâu!"); }
}

Animal a = new Dog();

if (a instanceof Dog d) {
    d.bark(); // Có thể gọi các phương thức Dog mà không cần ép kiểu!
}

Nhắc lại, thứ tự kiểm tra rất quan trọng: hãy đi từ cụ thể đến tổng quát, nếu không các kiểm tra “hẹp” có thể không khớp.

So sánh: cách cũ và cách mới

Cách cũ Cách mới (pattern matching)
if (obj instanceof Cat) {
    Cat c = (Cat) obj;
    c.meow();
}
if (obj instanceof Cat c) {
    c.meow();
}

5. Hạn chế của pattern matching cho instanceof

  • Phạm vi của biến. Biến từ mẫu chỉ nhìn thấy trong nhánh nơi kiểm tra là đúng.
if (obj instanceof String s) {
    System.out.println(s); // s khả dụng
}
// System.out.println(s); // Lỗi! s không nhìn thấy ở đây
  • Không thể khai báo nhiều biến kiểu khác nhau trong cùng một điều kiện.
// Lỗi biên dịch:
if (obj instanceof String s || obj instanceof Integer i) {
    // ...
}
  • Cần Java 16+. Trên các phiên bản JDK cũ hơn, cú pháp mới không được hỗ trợ.

6. Ví dụ thực tế (dựa trên một ứng dụng đơn giản)

Hãy hình dung một Task Manager đơn giản với nhiều loại nhiệm vụ.

Các lớp

class Task {
    String title;
    public Task(String title) { this.title = title; }
}

class BugTask extends Task {
    int severity;
    public BugTask(String title, int severity) {
        super(title);
        this.severity = severity;
    }
}

class FeatureTask extends Task {
    String feature;
    public FeatureTask(String title, String feature) {
        super(title);
        this.feature = feature;
    }
}

Xử lý với pattern matching

public static void processTask(Task t) {
    if (t instanceof BugTask bug) {
        System.out.println("Bug: " + bug.title + ", mức độ nghiêm trọng: " + bug.severity);
    } else if (t instanceof FeatureTask feature) {
        System.out.println("Tính năng: " + feature.title + ", mô-đun: " + feature.feature);
    } else if (t instanceof Task task) {
        System.out.println("Nhiệm vụ thường: " + task.title);
    }
}

7. Những lưu ý hữu ích

Bảng: Pattern Matching cho instanceof — ưu và nhược

Ưu điểm Nhược điểm/Hạn chế
Ít mã hơn, dễ đọc hơn Yêu cầu Java 16+
Không có rủi ro ClassCastException Biến chỉ nhìn thấy trong khối if
An toàn kiểu ở mức trình biên dịch Không hoạt động cho nhiều kiểu trong cùng một điều kiện
Thuận tiện khi xử lý kế thừa Có thể không được hỗ trợ trong IDE/bản build cũ
Phù hợp với mọi lớp

Sơ đồ trực quan: pattern matching cho instanceof hoạt động như thế nào

+---------------------------+
|      Object obj           |
+---------------------------+
            |
            v
  if (obj instanceof Type t)
            |
      Có            Không
   (true)        (false)
    |               |
    v               v
 t khả dụng     t không tồn tại
   (mã)          (không truy cập)

8. Lỗi thường gặp khi dùng pattern matching cho instanceof

Lỗi #1: Cố dùng biến ngoài khối if. Bạn khai báo biến trong mẫu, ra khỏi khối — biến không còn nữa. Trình biên dịch sẽ thắc mắc: “s là ai vậy?”

Lỗi #2: Kỳ vọng rằng instanceof hoạt động với null. Nếu đối tượng bằng null, điều kiện instanceof luôn sai, biến sẽ không được tạo. Hãy xử lý null riêng khi cần.

Lỗi #3: Dùng cú pháp mới trên phiên bản JDK/IDE cũ. Trên Java 11 trở xuống, pattern matching cho instanceof không khả dụng — bạn sẽ nhận lỗi cú pháp. Hãy kiểm tra phiên bản JDK.

Lỗi #4: Nhầm lẫn về phạm vi. Biến từ mẫu chỉ khả dụng trong nhánh nơi kiểm tra đúng. Bên ngoài — nó không tồn tại.

Lỗi #5: Mong đợi hỗ trợ nhiều kiểu đồng thời. Không thể khai báo ngay hai biến kiểu khác nhau trong cùng một điều kiện: if (obj instanceof String s || obj instanceof Integer i) — không làm được như vậy. Mỗi kiểu — một kiểm tra riêng.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION