Tổng quan các tính năng mới của Java 22 & 23
JDK 22 và JDK 23 đều là phiên bản non-LTS (long-term support), Oracle thường chỉ cung cấp bản cập nhật trong sáu tháng cho loại phiên bản này. Bản long-term support tiếp theo là JDK 25, phát hành vào tháng 9 năm 2025.
Hình dưới đây thể hiện số lượng tính năng mới và thời điểm cập nhật của từng phiên bản từ JDK 8 đến JDK 24:

Do JDK 22 và JDK 23 có khá nhiều tính năng mới trùng nhau, ở đây chủ yếu giới thiệu JDK 23, đồng thời bổ sung một số tính năng riêng của JDK 22.
JDK 23 có tổng cộng 12 tính năng mới:
- JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview) (Primitive Types trong pattern,
instanceofvàswitch, preview) - JEP 466: Class File API (Second Preview) (Class File API, preview lần thứ hai)
- JEP 467: Markdown Documentation Comments (Documentation comments bằng Markdown)
- JEP 469: Vector API (Eighth Incubator) (Vector API, incubator lần thứ tám)
- JEP 473: Stream Gatherers (Second Preview) (Stream Gatherers, preview lần thứ hai)
- JEP 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal (Deprecate các phương thức memory access trong sun.misc.Unsafe để loại bỏ)
- JEP 474: ZGC: Generational Mode by Default (ZGC: generational mode mặc định)
- JEP 476: Module Import Declarations (Preview) (Khai báo module import, preview)
- JEP 477: Unnamed Classes and Instance Main Methods (Third Preview) (Unnamed Classes và instance main method, preview lần thứ ba)
- JEP 480: Structured Concurrency (Third Preview) (Structured Concurrency, preview lần thứ ba)
- JEP 481: Scoped Values (Third Preview) (Scoped Values, preview lần thứ ba)
- JEP 482: Flexible Constructor Bodies (Second Preview) (Flexible Constructor Bodies, preview lần thứ hai)
JDK 22 có tổng cộng 12 tính năng mới, như sau:

Trong đó, tôi sẽ giới thiệu chi tiết riêng 4 tính năng mới dưới đây:
- JEP 423: G1 Region Pinning
- JEP 454: Foreign Function & Memory API
- JEP 456: Unnamed Patterns and Variables
- JEP 458: Launch Multi-File Source-Code Programs
JDK 23
JEP 455: Primitive Types trong pattern, instanceof và switch (preview)
Trước JEP 455, instanceof chỉ hỗ trợ reference type; label case của biểu thức và statement switch chỉ có thể sử dụng integer literal, enum constant và string literal.
Trong tính năng preview của JEP 455, instanceof và switch hỗ trợ đầy đủ mọi primitive type, bao gồm byte, short, char, int, long, float, double, boolean.
// Cách viết truyền thống
if (i >= -128 && i <= 127) {
byte b = (byte)i;
... b ...
}
// Cải tiến bằng instanceof
if (i instanceof byte b) {
... b ...
}
long v = ...;
// Cách viết truyền thống
if (v == 1L) {
// ...
} else if (v == 2L) {
// ...
} else if (v == 10_000_000_000L) {
// ...
}
// Sử dụng label case với kiểu long
switch (v) {
case 1L:
// ...
break;
case 2L:
// ...
break;
case 10_000_000_000L:
// ...
break;
default:
// ...
}JEP 466: Class File API (preview lần thứ hai)
Class File API đã được preview lần đầu trong JDK 22, do JEP 457 đề xuất.
Mục tiêu của Class File API là cung cấp một API tiêu chuẩn để phân tích, tạo và chuyển đổi Java class file, thay thế việc phải phụ thuộc vào các thư viện bên thứ ba (như ASM) khi xử lý class file.
// Tạo một đối tượng ClassFile, đây là entry point để thao tác với class file.
ClassFile cf = ClassFile.of();
// Phân tích byte array thành ClassModel
ClassModel classModel = cf.parse(bytes);
// Xây dựng class file mới, loại bỏ mọi method bắt đầu bằng "debug"
byte[] newBytes = cf.build(classModel.thisClass().asSymbol(),
classBuilder -> {
// Duyệt qua mọi class element
for (ClassElement ce : classModel) {
// Kiểm tra có phải method và tên method bắt đầu bằng "debug" hay không
if (!(ce instanceof MethodModel mm
&& mm.methodName().stringValue().startsWith("debug"))) {
// Thêm vào class file mới
classBuilder.with(ce);
}
}
});JEP 467: Markdown Documentation Comments
Có thể sử dụng cú pháp Markdown trong documentation comments của JavaDoc, thay cho cách trước đây vốn chỉ có thể sử dụng HTML và JavaDoc tag.
Markdown ngắn gọn, dễ đọc hơn, giảm sự rườm rà khi viết HTML thủ công, đồng thời vẫn hỗ trợ các HTML element và JavaDoc tag. Cải tiến này nhằm giúp việc viết và đọc documentation comments cho API dễ dàng hơn mà không ảnh hưởng đến cách diễn giải các comment hiện có. Markdown cung cấp cách biểu đạt đơn giản hơn cho các phần tử documentation phổ biến (như paragraph, list, link...), cải thiện khả năng bảo trì của documentation comments và developer experience.

JEP 469: Vector API (incubator lần thứ tám)
Vector computation gồm một chuỗi phép toán trên vector. Vector API dùng để biểu đạt vector computation; tại runtime, computation này có thể được compile một cách đáng tin cậy thành vector instruction tối ưu trên CPU architecture được hỗ trợ, nhờ đó đạt performance tốt hơn scalar computation tương đương.
Mục tiêu của Vector API là cung cấp cho người dùng cách biểu đạt vector computation phong phú, ngắn gọn, dễ sử dụng và độc lập với platform.
Đây là scalar computation đơn giản trên các phần tử của array:
void scalarComputation(float[] a, float[] b, float[] c) {
for (int i = 0; i < a.length; i++) {
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
}
}Đây là vector computation tương đương sử dụng Vector API:
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
void vectorComputation(float[] a, float[] b, float[] c) {
int i = 0;
int upperBound = SPECIES.loopBound(a.length);
for (; i < upperBound; i += SPECIES.length()) {
// FloatVector va, vb, vc;
var va = FloatVector.fromArray(SPECIES, a, i);
var vb = FloatVector.fromArray(SPECIES, b, i);
var vc = va.mul(va)
.add(vb.mul(vb))
.neg();
vc.intoArray(c, i);
}
for (; i < a.length; i++) {
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
}
}JEP 473: Stream Gatherers (preview lần thứ hai)
Stream Gatherers đã được preview lần đầu trong JDK 22, do JEP 461 đề xuất.
Cải tiến này cho phép Stream API hỗ trợ intermediate operation tùy chỉnh.
source.gather(a).gather(b).gather(c).collect(...)JEP 471: Deprecate các phương thức memory access trong sun.misc.Unsafe
JEP 471 đề xuất deprecate các phương thức memory access của sun.misc.Unsafe; các phương thức này sẽ bị loại bỏ trong những phiên bản tương lai.
Những phương thức không an toàn này đã có các giải pháp thay thế an toàn và hiệu quả:
java.lang.invoke.VarHandle: được giới thiệu trong JDK 9 (JEP 193), cung cấp một cách an toàn và hiệu quả để thao tác với heap memory, bao gồm field của object, static field của class và phần tử array.java.lang.foreign.MemorySegment: được giới thiệu trong JDK 22 (JEP 454), cung cấp một cách an toàn và hiệu quả để truy cập off-heap memory, đôi khi phối hợp vớiVarHandle.
MemorySegment là một trong các core type của Foreign Function & Memory API, dùng để truy cập an toàn heap memory hoặc off-heap memory; VarHandle là một standard API độc lập, có thể dùng để truy cập field, phần tử array hoặc truy cập data theo memory layout. Foreign Function & Memory API trở thành tính năng chính thức trong JDK 22.
import java.lang.foreign.*;
import java.lang.invoke.VarHandle;
// Class quản lý off-heap integer array
class OffHeapIntBuffer {
// VarHandle dùng để truy cập các integer element
private static final VarHandle ELEM_VH = ValueLayout.JAVA_INT.arrayElementVarHandle();
// Memory manager
private final Arena arena;
// Off-heap memory segment
private final MemorySegment buffer;
// Constructor cấp phát không gian cho số lượng integer được chỉ định
public OffHeapIntBuffer(long size) {
this.arena = Arena.ofShared();
this.buffer = arena.allocate(ValueLayout.JAVA_INT, size);
}
// Giải phóng memory
public void deallocate() {
arena.close();
}
// Thiết lập giá trị tại index được chỉ định theo volatile
public void setVolatile(long index, int value) {
ELEM_VH.setVolatile(buffer, 0L, index, value);
}
// Khởi tạo các element trong range được chỉ định về 0
public void initialize(long start, long n) {
buffer.asSlice(ValueLayout.JAVA_INT.byteSize() * start,
ValueLayout.JAVA_INT.byteSize() * n)
.fill((byte) 0);
}
// Copy các element trong range được chỉ định vào array mới
public int[] copyToNewArray(long start, int n) {
return buffer.asSlice(ValueLayout.JAVA_INT.byteSize() * start,
ValueLayout.JAVA_INT.byteSize() * n)
.toArray(ValueLayout.JAVA_INT);
}
}JEP 474: ZGC: generational mode mặc định
Mode mặc định của Z Garbage Collector (ZGC) được chuyển sang generational mode, đồng thời non-generational mode bị deprecate và dự kiến bị loại bỏ trong các phiên bản tương lai. Generational ZGC là lựa chọn tốt hơn trong phần lớn trường hợp.
JEP 476: Module Import Declarations (preview)
Module import declaration cho phép import ngắn gọn toàn bộ package được export từ một module trong Java code mà không cần khai báo import cho từng package. Tính năng này đơn giản hóa việc tái sử dụng modular library, đặc biệt khi sử dụng nhiều module, tránh phải viết số lượng lớn package import declaration, giúp developer truy cập third-party library và Java core class thuận tiện hơn.
Tính năng này đặc biệt hữu ích cho người mới học và việc phát triển prototype, vì không yêu cầu developer phải modularize code của mình, đồng thời vẫn tương thích với cách import truyền thống, cải thiện development efficiency và code readability.
// Import toàn bộ module java.base, developer có thể trực tiếp truy cập các class như List, Map, Stream mà không cần import package thủ công mỗi lần
import module java.base;
public class Example {
public static void main(String[] args) {
String[] fruits = { "apple", "berry", "citrus" };
Map<String, String> fruitMap = Stream.of(fruits)
.collect(Collectors.toMap(
s -> s.toUpperCase().substring(0, 1),
Function.identity()));
System.out.println(fruitMap);
}
}JEP 477: Unnamed Classes và instance main method (preview lần thứ ba)
Tính năng này chủ yếu đơn giản hóa việc khai báo main method. Với người mới học Java, cách khai báo main method này đưa vào quá nhiều khái niệm cú pháp Java, gây khó khăn cho việc nhanh chóng làm quen.
Định nghĩa main method trước khi sử dụng tính năng này:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}Định nghĩa main method sau khi sử dụng tính năng mới:
class HelloWorld {
void main() {
System.out.println("Hello, World!");
}
}Đơn giản hóa thêm (unnamed class cho phép bỏ qua tên class):
void main() {
System.out.println("Hello, World!");
}JEP 480: Structured Concurrency (preview lần thứ ba)
Java 19 giới thiệu Structured Concurrency dưới dạng incubator API. Trong JDK 23, API này đang ở giai đoạn preview lần thứ ba, nhằm đơn giản hóa lập trình multi-thread, không nhằm thay thế java.util.concurrent.
Structured Concurrency coi nhiều task chạy trong các thread khác nhau là một đơn vị công việc duy nhất, nhờ đó đơn giản hóa error handling, nâng cao reliability và tăng observability. Nói cách khác, Structured Concurrency giữ lại readability, maintainability và observability của code single-thread.
API cơ bản của Structured Concurrency là StructuredTaskScope. StructuredTaskScope hỗ trợ chia task thành nhiều concurrent subtask, thực thi chúng trong các thread riêng, và các subtask phải hoàn thành trước khi task chính tiếp tục.
Cách sử dụng cơ bản của StructuredTaskScope như sau:
try (var scope = new StructuredTaskScope<Object>()) {
// Dùng method fork để tạo thread thực thi subtask
Subtask<Integer> subtask1 = scope.fork(task1);
Subtask<String> subtask2 = scope.fork(task2);
// Chờ thread hoàn thành
scope.join();
// Xử lý result có thể bao gồm xử lý hoặc rethrow exception
... process results/exceptions ...
} // closeStructured Concurrency rất phù hợp với virtual thread, đây là loại thread nhẹ do JDK triển khai. Nhiều virtual thread dùng chung một operating system thread, nhờ đó cho phép tạo số lượng virtual thread rất lớn.
JEP 481: Scoped Values (preview lần thứ ba)
Scoped Values có thể chia sẻ immutable data trong cùng thread và giữa các thread, ưu việt hơn thread-local variables, đặc biệt khi sử dụng số lượng lớn virtual thread.
final static ScopedValue<...> V = ScopedValue.newInstance();
// Trong một method nào đó
ScopedValue.where(V, <value>)
.run(() -> { ... V.get() ... call methods ... });
// Trong một method được gọi trực tiếp hoặc gián tiếp từ lambda expression
... V.get() ...Scoped Values cho phép chia sẻ data an toàn và hiệu quả giữa các component trong chương trình lớn mà không cần dựa vào method parameter.
JEP 482: Flexible Constructor Bodies (preview lần thứ hai)
Tính năng này ban đầu được giới thiệu trong JDK 22 bởi JEP 447: Statements before super(...) (Preview).
Java yêu cầu trong constructor, lời gọi super(...) hoặc this(...) phải là statement đầu tiên. Điều này có nghĩa là chúng ta không thể trực tiếp initialize field trong subclass constructor trước khi gọi parent class constructor.
Flexible Constructor Bodies giải quyết vấn đề này, cho phép viết statement trong constructor body trước khi gọi super(..) hoặc this(..). Các statement này có thể initialize field nhưng không được reference đến instance đang được construct. Nhờ đó, ngăn việc field của subclass chưa được initialize đúng khi parent class constructor gọi method của subclass, tăng reliability của class construction.
Tính năng này giải quyết vấn đề trước đây khi Java syntax giới hạn cách tổ chức code của constructor, cho phép developer biểu đạt hành vi của constructor tự do và tự nhiên hơn, chẳng hạn trực tiếp kiểm tra, chuẩn bị và chia sẻ tham số trong constructor mà không cần dựa vào helper method hoặc constructor, cải thiện readability và maintainability của code.
class Person {
private final String name;
private int age;
public Person(String name, int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative.");
}
this.name = name; // Initialize field trước khi gọi parent class constructor
this.age = age;
// ... Code initialization khác
}
}
class Employee extends Person {
private final int employeeId;
public Employee(String name, int age, int employeeId) {
this.employeeId = employeeId; // Initialize field trước khi gọi parent class constructor
super(name, age); // Gọi parent class constructor
// ... Code initialization khác
}
}JDK 22
JEP 423: G1 Region Pinning
JEP 423 đề xuất triển khai tính năng Region Pinning trong G1 garbage collector, nhằm giảm vấn đề latency do các JNI critical region gây ra.
Các object trong JNI critical region không thể bị di chuyển khi garbage collection, vì vậy trước đây G1 giải quyết vấn đề này bằng cách disable garbage collection, dẫn đến thread bị block và latency nghiêm trọng. Bằng cách đưa cơ chế Region Pinning vào old generation và young generation của G1, G1 có thể pin memory region chứa object trong critical region, đồng thời tiếp tục collect các region chưa bị pin, loại bỏ nhu cầu disable garbage collection. Cải tiến này giúp giảm đáng kể latency, nâng cao throughput và stability của system khi tương tác với JNI.
JEP 454: Foreign Function and Memory API
Java program có thể dùng API này để tương tác với code và data bên ngoài Java runtime. Bằng cách gọi hiệu quả external function (tức code bên ngoài JVM) và truy cập an toàn external memory (tức memory không do JVM quản lý), API này cho phép Java program gọi native library và xử lý native data mà không mang những rủi ro và sự mong manh như JNI.
Foreign Function and Memory API được incubate lần đầu trong Java 17 theo JEP 412. Java 18 là lần incubate thứ hai theo JEP 419. Trong Java 19, đây là preview lần đầu theo JEP 424. Trong JDK 20, đây là preview lần thứ hai theo JEP 434. Trong JDK 21, đây là preview lần thứ ba theo JEP 442.
Cuối cùng, tính năng này đã trở thành tính năng chính thức trong JDK 22.
Trong Tổng quan các tính năng mới trong Java 19, tôi đã giới thiệu chi tiết về Foreign Function and Memory API, nên ở đây không giới thiệu thêm.
JEP 456: Unnamed Patterns and Variables
Unnamed Patterns and Variables được preview trong JDK 21 bởi JEP 443, và đã trở thành tính năng chính thức trong JDK 22.
Bạn có thể xem giới thiệu chi tiết về tính năng mới này trong bài viết Tổng quan các tính năng mới trong Java 21 (quan trọng).
JEP 458: Launch Multi-File Source-Code Programs
Java 11 giới thiệu JEP 330: Launch Single-File Source-Code Programs, mở rộng chức năng của Java launcher, cho phép chạy trực tiếp một Java source file. Với command java HelloWorld.java, Java có thể compile ngầm source code trong memory và thực thi ngay mà không cần tạo file .class trên disk. Điều này đơn giản hóa workflow của developer khi viết tool program nhỏ hoặc học Java, tránh bước compile thủ công.
Giả sử file Prog.java khai báo hai class:
class Prog {
public static void main(String[] args) { Helper.run(); }
}
class Helper {
static void run() { System.out.println("Hello!"); }
}Command java Prog.java sẽ compile hai class trong memory và thực thi method main của class đầu tiên được khai báo trong file này.
Cách này có một hạn chế: toàn bộ source code của program phải nằm trong một file .java.
JEP 458: Launch Multi-File Source-Code Programs là phần mở rộng của chức năng JEP 330, cho phép chạy trực tiếp program gồm nhiều Java source file mà không cần bước compile tường minh.
Giả sử trong một directory có hai Java source file Prog.java và Helper.java, mỗi file khai báo một class:
// Prog.java
class Prog {
public static void main(String[] args) { Helper.run(); }
}
// Helper.java
class Helper {
static void run() { System.out.println("Hello!"); }
}Khi chạy command java Prog.java, Java launcher sẽ compile trong memory và thực thi method main của class Prog. Vì code trong class Prog tham chiếu đến class Helper, launcher sẽ tự động tìm file Helper.java trong file system, compile class Helper trong đó và thực thi nó trong memory. Quá trình này là tự động; developer không cần gọi rõ ràng javac để compile toàn bộ source file.
Tính năng này giúp chuyển từ project nhỏ sang project lớn mượt mà hơn. Developer có thể tự do lựa chọn thời điểm đưa build tool vào sử dụng, tránh bị buộc phải thiết lập project structure phức tạp khi iteration nhanh. Tính năng này loại bỏ giới hạn single-file, tiếp tục đơn giản hóa quá trình phát triển từ single-file sang multi-file program, đặc biệt phù hợp với prototype development, thử nghiệm nhanh và giai đoạn khám phá project ban đầu.
