JEP 430: Mẫu Chuỗi (String Templates) – Phiên Bản Thử Nghiệm
Một trong những cải tiến nổi bật trong Java 21 là String Templates, cho phép xây dựng chuỗi động một cách trực quan và gọn gàng hơn. Trước đây, lập trình viên phải dùng nối chuỗi, String.format(), hoặc StringBuilder, đều có nhược điểm về độ rõ ràng và hiệu suất.
Với mẫu chuỗi, bạn có thể nhúng biểu thức trực tiếp vào chuỗi bằng cú pháp \{}. Ví dụ:
String name = "Nguyen";
String message = STR."Xin chào \{name}!";
Ở đây, STR là một trình xử lý mẫu tích hợp sẵn. Java cung cấp ba trình xử lý chính:
- STR: Thực hiện nội suy đơn thuần – thay thế biểu thức bằng giá trị chuỗi tương ứng.
- FMT: Hỗ trợ định dạng nâng cao, ví dụ:
FMT."Giá trị: \{value, .2f}". - RAW: Không xử lý ngay mà trả về đối tượng
StringTemplate, hữu ích khi cần kiểm soát quá trình xử lý.
Bạn cũng có thể tạo trình xử lý riêng bằng cách triển khai interface StringTemplate.Processor. Biểu thức bên trong \{} có thể là biến cục bộ, trường, phương thức, hay thậm chí là phép tính:
int a = 5, b = 7;
String result = STR."\{a} + \{b} = \{a + b}"; // "5 + 7 = 12"
Tính năng này giúp mã nguồn dễ đọc hơn, đặc biệt khi làm việc với các chuỗi phức tạp như truy vấn SQL hay HTML.
JEP 431: Tập Hợp Thứ Tự (Sequenced Collections)
Java 21 giới thiệu hệ thống giao diện mới để chuẩn hóa hành vi của các tập hợp có thứ tự cố định: SequencedCollection, SequencedSet, và SequencedMap. Các giao diện này cung cấp phương thức nhất quán để truy cập phần tử đầu/cuối và lấy chế độ xem đảo ngược.
Ví dụ với SequencedCollection:
ArrayList<String> list = new ArrayList<>();
list.add("B");
list.addFirst("A"); // [A, B]
list.addLast("C"); // [A, B, C]
String first = list.getFirst(); // A
String last = list.getLast(); // C
List<String> reversed = list.reversed(); // [C, B, A]
LinkedHashSet và LinkedHashMap đã hỗ trợ các hành vi này từ trước. JEP 431 đơn giản hóa API bằng cách thêm các phương thức tiêu chuẩn, giúp code đồng nhất và dễ bảo trì hơn khi làm việc với nhiều loại tập hợp.
JEP 439: ZGC Thế Hệ (Generational ZGC)
ZGC, bộ thu gom rác tốc độ cao, giờ đây được bổ sung mô hình thế hệ – phân vùng heap thành vùng mới (young) và cũ (old). Điều này phù hợp với thực tế rằng đa số đối tượng chết nhanh chóng sau khi tạo.
Để kích hoạt tính năng này, sử dụng cờ lệnh:
java -XX:+UseZGC -XX:+ZGenerational MyApp
So với ZGC không chia thế hệ, phiên bản thế hệ giảm đáng kể thời gian tạm dừng, đặc biệt trong các ứng dụng có tỷ lệ tạo đối tượng cao. Oracle dự kiến sẽ đặt -XX:+ZGenerational làm mặc định trong các phiên bản sắp tới, và cuối cùng loại bỏ chế độ không chia thế hệ.
JEP 440: Mẫu Bản Ghi (Record Patterns)
Sau nhiều lần thử nghiệm, Record Patterns chính thức ra mắt trong Java 21. Tính năng này cho phép giải cấu trúc (destructure) các bản ghi (record) một cách trực tiếp trong biểu thức mẫu.
Ví dụ:
record Point(int x, int y) {}
record Circle(Point center, double radius) {}
void process(Circle c) {
if (c instanceof Circle(Point(int x, int y), double r)) {
System.out.println("Tọa độ: (" + x + ", " + y + "), Bán kính: " + r);
}
}
Thay vì gọi từng getter, bạn có thể trích xuất dữ liệu lồng nhau chỉ trong một dòng điều kiện, làm cho code ngắn gọn và an toàn kiểu hơn.
JEP 441: Mở Rộng Mẫu Trong switch
Tiếp nối JEP 440, mẫu trong câu lệnh switch giờ đây hỗ trợ đầy đủ các kiểu mẫu, bao gồm mẫu bản ghi và mẫu kiểu.
Ví dụ sử dụng mẫu kiểu:
Object obj = "Hello";
String output = switch (obj) {
case Integer i -> "Số nguyên: " + i;
case String s -> "Chuỗi: " + s.toUpperCase();
case null -> "Null";
default -> "Không xác định";
};
Kết hợp với yield, switch trở thành một biểu thức mạnh mẽ để xử lý đa hình mà không cần chuỗi if-else dài dòng.
JEP 442: API Hàm và Bộ Nhớ Ngoại Vi (Lần Thử Nghiệm Thứ Ba)
Tính năng này nhằm thay thế JNI bằng một cơ chế an toàn và hiệu quả hơn để tương tác với thư viện hệ thống và bộ nhớ ngoài JVM. Với Foreign Function & Memory API, bạn có thể:
- Gọi hàm C/C++ trực tiếp.
- Truy cập vùng nhớ được cấp phát bên ngoài heap Java.
Ví dụ mở tệp bằng API hệ điều hành:
try (var linker = Linker.nativeLinker()) {
var fopen = linker.downcallHandle(
CLinker.systemLookup().lookup("fopen").get(),
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS)
);
}
Phiên bản thử nghiệm thứ ba cho thấy sự trưởng thành của API, hứa hẹn ổn định trong phiên bản kế tiếp.
JEP 443: Biến và Mẫu Vô Danh (Unnamed Patterns and Variables)
Giúp tăng tính rõ ràng khi một biến hoặc thành phần mẫu không cần dùng đến. Ký tự gạch dưới _ được dùng để đại diện cho chúng.
Ví dụ:
// Biến tài nguyên không dùng
try (var _ = DatabaseConnection.open()) {
log.info("Kết nối đã được khởi tạo.");
}
// Bắt ngoại lệ không xử lý
catch (IOException _) {
retryOperation();
}
// Mẫu bản ghi bỏ qua thành phần
if (point instanceof Point(int x, _)) {
System.out.println("Tọa độ X: " + x);
}
Tính năng này khuyến khích viết code sạch hơn, minh bạch hóa ý định "bỏ qua" giá trị.
JEP 444: Luồng Ảo (Virtual Threads)
Luồng ảo là bước đột phá lớn trong xử lý song song. Khác với luồng nền tảng (platform thread) – ánh xạ 1-1 với luồng OS và tiêu tốn nhiều tài nguyên – luồng ảo được quản lý bởi JVM, nhẹ và có thể tạo hàng triệu instance.
Ví dụ tạo hàng ngàn tác vụ:
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return "Hoàn tất";
});
}
}
So với pool luồng truyền thống, luồng ảo gần như loại bỏ chi phí tạo/đổi ngữ cảnh, lý tưởng cho các ứng dụng I/O-heavy như server web.
JEP 445: Lớp và main Vô Danh (Thử Nghiệm)
Hướng đến người mới học, JEP 445 đơn giản hóa điểm vào chương trình. Bạn không cần khai báo lớp hay phương thức main theo chuẩn truyền thống:
void main() {
System.out.println("Chào thế giới!");
}
Code trên hoàn toàn hợp lệ trong Java 21 nếu được chạy như một file nguồn đơn. JVM sẽ tự động bao bọc nó trong một lớp vô danh. Tính năng này giúp người mới tập trung vào logic thay vì cú pháp.