1. Giới thiệu
Pattern Matching trong Java là khả năng kiểm tra một đối tượng với một mẫu và trích xuất dữ liệu từ nó một cách an toàn và ngắn gọn. Thay vì sử dụng kiểm tra instanceof
kèm theo ép kiểu, pattern matching cho phép bạn kết hợp các thao tác này lại với nhau.
2. Pattern Matching cho instanceof
Trước Java 16:
java
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.toUpperCase());
}
Với Pattern Matching:
java
if (obj instanceof String s) {
System.out.println(s.toUpperCase());
}
Điểm nổi bật:
- Loại bỏ việc ép kiểu không cần thiết.
- Biến
s
chỉ có sẵn trong khốiif
. - Hoạt động với phạm vi luồng: nếu trình biên dịch biết
obj
là mộtString
, bạn có thể sử dụng nó.
3. Pattern Matching cho switch
switch
truyền thống:
java
static String format(Object obj) {
return switch (obj) {
case Integer i -> "int " + i;
case Long l -> "long " + l;
case String s -> "String " + s.toUpperCase();
default -> obj.toString();
};
}
Tính năng:
- Không cần ép kiểu rõ ràng.
- Hỗ trợ các lớp sealed (xem phần tiếp theo).
- Có thể khớp với null an toàn bằng
case null
.
4. Record Patterns
Records rất hữu ích cho việc lưu trữ dữ liệu. Record patterns cho phép bạn phân tách chúng bên trong switch
hoặc if
.
java
record Point(int x, int y) {}
static String printPoint(Object obj) {
return switch (obj) {
case Point(int x, int y) -> "Point tại (" + x + ", " + y + ")";
default -> "Không phải là một điểm";
};
}
Record patterns lồng nhau:
java
record Rectangle(Point topLeft, Point bottomRight) {}
static void printRectangle(Rectangle r) {
if (r instanceof Rectangle(Point(int x1, int y1), Point(int x2, int y2))) {
System.out.println("Hình chữ nhật từ (" + x1 + "," + y1 + ") đến (" + x2 + "," + y2 + ")");
}
}
5. Sealed Types với Pattern Matching
Các lớp sealed cho phép bạn kiểm soát việc kế thừa. Pattern matching hoạt động hoàn hảo với chúng.
java
sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
static double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
};
}
Vì Shape
là sealed, trình biên dịch kiểm tra tính đầy đủ — không cần default
.
6. Guarded Patterns
Đôi khi bạn cần một điều kiện bổ sung cho một trường hợp.
java
static String typeOfNumber(Number n) {
return switch (n) {
case Integer i when i > 0 -> "số nguyên dương";
case Integer i -> "số nguyên không dương";
case Long l when l > 0 -> "số nguyên dài dương";
default -> "số khác";
};
}
7. Record Patterns trong vòng lặp for
Bạn có thể phân tách các record trực tiếp trong vòng lặp.
java
record Point(int x, int y) {}
List<Point> points = List.of(new Point(1, 2), new Point(3, 4));
for (Point(int x, int y) : points) {
System.out.println("x=" + x + ", y=" + y);
}
8. Primitive Patterns
Pattern matching được mở rộng đến các kiểu nguyên thủy. Điều này cho phép xử lý số một cách ngắn gọn hơn.
java
static String describe(Object obj) {
return switch (obj) {
case int i -> "int: " + i;
case long l -> "long: " + l;
case double d -> "double: " + d;
case null -> "giá trị null";
default -> "không xác định";
};
}
Lợi ích của việc sử dụng Primitive Patterns:
- Loại bỏ overhead của boxing/unboxing và biến pattern matching trở nên phổ quát.
9. Các Thực Hành Tốt Nhất
- Luôn sử dụng pattern matching khi có thể để cải thiện tính rõ ràng của mã.
- Kiểm tra các trường hợp biên để đảm bảo mã của bạn an toàn trước các loại dữ liệu không mong muốn.
10. Những Cạm Bẫy Thường Gặp
- Không sử dụng pattern matching với các kiểu dữ liệu không rõ ràng có thể dẫn đến lỗi.
- Bỏ qua kiểm tra
null
có thể gây ra NullPointerException.
11. Mẹo Tối Ưu Hiệu Suất
- Sử dụng pattern matching thay cho các cấu trúc điều kiện phức tạp để cải thiện hiệu suất và khả năng đọc mã.
- Giảm thiểu số lần ép kiểu không cần thiết có thể làm giảm hiệu suất.
FAQ
Q: Pattern matching có hỗ trợ cho tất cả các kiểu dữ liệu không?
A: Không, pattern matching chủ yếu hỗ trợ cho các kiểu dữ liệu đã được định nghĩa rõ ràng như record
, sealed
, và các kiểu nguyên thủy.
Q: Có thể kết hợp pattern matching với các thư viện khác không?
A: Có, bạn có thể sử dụng pattern matching trong các thư viện Java thông thường mà bạn đang sử dụng.
Kết luận
Pattern matching trong Java mang lại nhiều lợi ích cho lập trình viên, giúp mã nguồn trở nên rõ ràng và dễ bảo trì hơn. Hãy thử áp dụng pattern matching trong dự án của bạn để trải nghiệm những lợi ích mà nó mang lại!