Tổng quan các tính năng mới của Java 9
Java 9 được phát hành vào ngày 21 tháng 9 năm 2017. Là phiên bản được phát hành sau Java 8 ba năm rưỡi, Java 9 mang đến nhiều thay đổi lớn. Trong đó, thay đổi quan trọng nhất là việc giới thiệu Java Platform Module System; ngoài ra còn có các thay đổi về collection, Stream...
JDK 9 không phải LTS (bản hỗ trợ dài hạn). Các phiên bản LTS hiện được Oracle liệt kê gồm JDK 8, JDK 11, JDK 17, JDK 21 và JDK 25.
Bài viết này sẽ chọn một số tính năng mới quan trọng để giới thiệu chi tiết:
- JEP 222: Java Shell Tool (JShell)
- JEP 261: Module System (Hệ thống module)
- JEP 248: G1 Becomes the Default Garbage Collector (G1 trở thành garbage collector mặc định)
- JEP 254: Compact Strings (Chuỗi compact)
- JEP 193: Variable Handles (Variable handles)
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 25:

JEP 222: Java Shell Tool (JShell)
JShell là một công cụ thực dụng được bổ sung trong Java 9. Nó cung cấp cho Java một công cụ tương tác dòng lệnh theo thời gian thực tương tự Python.
Trong JShell, bạn có thể nhập trực tiếp biểu thức và xem kết quả thực thi.

JShell mang lại những lợi ích nào?
- Hạ thấp rào cản để viết chương trình Java đầu tiên kiểu
"Hello World!", giúp người mới hứng thú hơn với việc học. - Khi xử lý logic nhỏ hoặc kiểm tra vấn đề đơn giản, JShell hiệu quả hơn IDE (không nhằm thay thế IDE; với việc kiểm tra logic phức tạp, IDE phù hợp hơn, hai công cụ bổ trợ cho nhau).
- ……
Code của JShell khác code thông thường có thể biên dịch ở điểm nào?
- Sau khi nhập xong một câu lệnh, JShell sẽ biên dịch và thực thi code trong background, sau đó trả về kết quả ngay, không cần người dùng tự chạy
javacvàjava. - JShell hỗ trợ khai báo lại biến; biến được khai báo sau sẽ ghi đè biến được khai báo trước.
- JShell hỗ trợ các biểu thức độc lập, chẳng hạn phép cộng thông thường
1 + 1. - ……
JEP 261: Module System (Hệ thống module)
Hệ thống module là một phần của Jigsaw Project, đưa thực tiễn phát triển theo module vào Java Platform, giúp code có khả năng tái sử dụng tốt hơn!
Hệ thống module là gì? Định nghĩa chính thức là:
A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor.
Nói đơn giản, bạn có thể xem một module là một tập hợp các package, resource và module descriptor (module-info.java) có tên duy nhất và có thể tái sử dụng.
Bất kỳ file jar nào cũng có thể được nâng cấp thành một module chỉ bằng cách thêm module descriptor (module-info.java).

Sau khi đưa vào hệ thống module, JDK được tổ chức lại thành 94 module. Ứng dụng Java có thể sử dụng công cụ jlink mới (jlink là công cụ dòng lệnh mới được phát hành cùng Java 9. Nó cho phép developer tạo JRE nhẹ, tùy chỉnh cho các ứng dụng Java dựa trên module) để tạo runtime image tùy chỉnh chỉ chứa các module JDK mà ứng dụng phụ thuộc. Nhờ đó, kích thước Java runtime có thể giảm đáng kể.
Chúng ta có thể dùng keyword exports để kiểm soát package nào được công khai cho bên ngoài sử dụng và công khai cho module nào.
module my.module {
// exports công khai tất cả thành viên public của package được chỉ định
exports com.my.package.name;
}
module my.module {
// exports ... to công khai package được chỉ định cho module được chỉ định
exports com.my.package.name to com.specific.module;
}Nếu muốn tìm hiểu sâu hơn về module trong Java 9, bạn có thể tham khảo các bài viết sau:
- 《Project Jigsaw: Module System Quick-Start Guide》
- 《Java 9 Modules: part 1》
- Giải mã Java 9 (2. Hệ thống module)
JEP 248: G1 Becomes the Default Garbage Collector (G1 trở thành garbage collector mặc định)
Trong Java 8, garbage collector mặc định là Parallel Scavenge (young generation) + Parallel Old (old generation). Đến Java 9, CMS garbage collector bị deprecated, G1 (Garbage-First Garbage Collector) trở thành garbage collector mặc định.
G1 được giới thiệu từ Java 7. Sau khi thể hiện hiệu năng xuất sắc qua hai phiên bản, nó trở thành garbage collector mặc định.
JEP 193: Variable Handles (Variable handle)
Variable handle là tham chiếu tới một biến hoặc một nhóm biến, bao gồm static field, non-static field, phần tử của array và các thành phần trong cấu trúc dữ liệu ngoài heap.
Ý nghĩa của variable handle tương tự method handle đã có là MethodHandle, được biểu diễn bởi Java class java.lang.invoke.VarHandle. Có thể tạo object VarHandle bằng các phương thức lookup của instance java.lang.invoke.MethodHandles.Lookup và các cách khác.
Sự xuất hiện của VarHandle thay thế một phần thao tác của java.util.concurrent.atomic và sun.misc.Unsafe. Đồng thời, nó cung cấp một loạt thao tác memory barrier tiêu chuẩn để kiểm soát memory ordering ở mức chi tiết hơn. Về tính an toàn, khả dụng và performance, nó đều tốt hơn API hiện có.
Cải tiến API
Không phải mọi thay đổi API đều được phát hành thông qua JEP (Java Enhancement Proposal).
Trong quy trình phát triển JDK: JEP thường được dùng cho các thay đổi lớn, chẳng hạn giới thiệu language feature mới, cơ chế JVM mới hoặc refactor library quy mô lớn. Những thao tác như thêm một vài factory method vào class hiện có, chẳng hạn List.of(), thường được xem là bảo trì library thông thường. Chúng được developer JDK trực tiếp submit và review thông qua ticket của JBS (JDK Bug System), sau đó được phát hành cùng phiên bản.
Cải tiến collection
Bổ sung các factory method như List.of(), Set.of(), Map.of() và Map.ofEntries() để tạo immutable collection (có phần giống Guava):
List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);Collection được tạo bằng of() là immutable collection, không thể thực hiện thao tác thêm, xóa, thay thế, sort... Nếu không, exception java.lang.UnsupportedOperationException sẽ được ném ra.
Cải tiến Stream
Stream được bổ sung các method mới ofNullable(), dropWhile(), takeWhile() và overload của method iterate().
Method ofNullable() trong Java 9 có thể tạo Stream một phần tử hoặc rỗng từ một giá trị có thể là null. Java 8 đã có thể dùng Stream.empty() để tạo stream rỗng, nhưng chưa có method tiện lợi để chuyển trực tiếp giá trị có thể null thành stream.
Stream<String> stringStream = Stream.ofNullable("Java");
System.out.println(stringStream.count());// 1
Stream<String> nullStream = Stream.ofNullable(null);
System.out.println(nullStream.count());//0Method takeWhile() lần lượt lấy các phần tử thỏa điều kiện từ Stream, dừng việc lấy khi gặp phần tử không thỏa điều kiện.
List<Integer> integerList = List.of(11, 33, 66, 8, 9, 13);
integerList.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 11 33Method dropWhile() có tác dụng ngược với takeWhile().
List<Integer> integerList2 = List.of(11, 33, 66, 8, 9, 13);
integerList2.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 66 8 9 13Overload mới của method iterate() cung cấp một tham số Predicate (điều kiện kiểm tra) để quyết định khi nào kết thúc việc lặp.
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
}
// overload mới được bổ sung
public static<T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) {
}Cách sử dụng hai method được so sánh dưới đây; overload mới của iterate() linh hoạt hơn.
// Dùng method iterate() ban đầu để output các số từ 1~10
Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// Dùng overload mới của iterate() để output các số từ 1~10
Stream.iterate(1, i -> i <= 10, i -> i + 1).forEach(System.out::println);Cải tiến Optional
Class Optional được bổ sung các method như ifPresentOrElse(), or() và stream().
Method ifPresentOrElse() nhận hai tham số Consumer và Runnable. Nếu Optional không rỗng, nó gọi tham số Consumer; nếu rỗng, nó gọi tham số Runnable.
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
Optional<Object> objectOptional = Optional.empty();
objectOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Empty!!!"));// Empty!!!Method or() nhận một tham số Supplier. Nếu Optional rỗng, nó trả về giá trị Optional do tham số Supplier chỉ định.
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
Optional<Object> objectOptional = Optional.empty();
objectOptional.or(() -> Optional.of("java")).ifPresent(System.out::println);//javaCải tiến String
Trong Java 8 và các phiên bản trước, String luôn được lưu trữ bằng char[]. Từ Java 9, implementation của String chuyển sang dùng array byte[] để lưu trữ chuỗi, giúp tiết kiệm dung lượng.
public final class String implements java.io.Serializable,Comparable<String>, CharSequence {
// Annotation @Stable cho biết biến nhiều nhất chỉ bị sửa một lần, được gọi là "ổn định".
@Stable
private final byte[] value;
}Cải tiến interface
Java 9 cho phép sử dụng private method trong interface. Nhờ đó, việc sử dụng interface linh hoạt hơn, phần nào giống một abstract class được đơn giản hóa.
public interface MyInterface {
private void methodPrivate(){
}
}Cải tiến IO
Trước Java 9, chúng ta chỉ có thể khai báo biến trong block try-with-resources:
try (Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
// omitted
}Từ Java 9, có thể sử dụng biến effectively-final trong câu lệnh try-with-resources.
final Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"));
try (scanner; writer) {
// omitted
}Biến effectively-final là gì? Nói đơn giản, đó là biến không được khai báo với final nhưng chưa từng thay đổi giá trị sau khi khởi tạo.
Như code trên minh họa, dù biến writer không được khai báo rõ ràng là final, nó không thay đổi sau lần được gán giá trị đầu tiên, nên là một biến effectively-final.
Process API
Java 9 bổ sung interface java.lang.ProcessHandle để quản lý native process, đặc biệt phù hợp để quản lý process chạy trong thời gian dài.
// Lấy process của JVM hiện đang chạy
ProcessHandle currentProcess = ProcessHandle.current();
// Output id của process
System.out.println(currentProcess.pid());
// Output thông tin của process
System.out.println(currentProcess.info());Tổng quan interface ProcessHandle:

Các cải tiến API khác
Reactive Streams
Trong class java.util.concurrent.Flow của Java 9, các interface cốt lõi của đặc tả Reactive Streams được bổ sung.
Flow bao gồm 4 interface cốt lõi là Flow.Publisher, Flow.Subscriber, Flow.Subscription và Flow.Processor. Java 9 cũng cung cấp SubmissionPublisher làm một implementation của Flow.Publisher.
Để tìm hiểu chi tiết hơn về Reactive Streams trong Java 9, bạn nên đọc bài viết Giải mã Java 9 (17. Reactive Streams ) - Lin Bản Thác.
Khác
- Cải tiến platform logging API: Java 9 cho phép JDK và ứng dụng sử dụng cùng một logging implementation. Bổ sung
System.LoggerFinderđể quản lý logging implementation mà JDK sử dụng. Trong runtime, JVM chỉ có một instanceLoggerFindertrên toàn hệ thống. Chúng ta có thể thêm implementationSystem.LoggerFindercủa riêng mình để JDK và ứng dụng sử dụng các logging framework khác như SLF4J. - Cải tiến class
CompletableFuture: Bổ sung một số method mới (completeAsync,orTimeout...). - Cải tiến Nashorn engine: Nashorn là JavaScript engine được giới thiệu từ Java 8. Java 9 cải tiến Nashorn, triển khai một số tính năng mới của ES6 (đã bị deprecated trong Java 11).
- Tính năng mới của I/O stream: Bổ sung method mới để đọc và copy dữ liệu trong
InputStream. - Cải thiện khả năng bảo mật của ứng dụng: Java 9 bổ sung 4 thuật toán hash SHA-3: SHA3-224, SHA3-256, SHA3-384 và SHA3-512.
- Cải tiến method handle (Method Handle): Method handle được giới thiệu từ Java 7. Java 9 bổ sung thêm nhiều static method trong class
java.lang.invoke.MethodHandlesđể tạo các loại method handle khác nhau. - ……
Tham khảo
- Java version history:https://en.wikipedia.org/wiki/Java_version_history
- Release Notes for JDK 9 and JDK 9 Update Releases : https://www.oracle.com/java/technologies/javase/9-all-relnotes.html
- 《Phân tích chuyên sâu các tính năng mới của Java》-Geek Time - JShell: Làm thế nào để nhanh chóng kiểm tra vấn đề đơn giản?
- New Features in Java 9: https://www.baeldung.com/new-java-9
- Java – Try with Resources:https://www.baeldung.com/java-try-with-resources
Lời cuối
Nếu nội dung hữu ích với bạn, hãy tiện tay tặng JavaGuide một Star miễn phí để ủng hộ: GitHub | Gitee.
JavaGuide đã được duy trì gần bảy năm, tích lũy 6100+ commit, với sự chung tay hoàn thiện của 620+ contributor. Star, phản hồi và PR của bạn đều là động lực để dự án tiếp tục cập nhật.
Nếu bạn đang chuẩn bị phỏng vấn backend / phát triển ứng dụng AI, có thể tham khảo Knowledge Planet của tôi, bao gồm các project thực tế về backend và AI, tối ưu CV, hỏi đáp 1-1 và tài liệu về các trọng điểm thường gặp, đã được duy trì liên tục sáu năm.
