Chúng ta vừa mới làm quen với Java 10 chưa được bao lâu, vậy mà Java 11 đã chính thức ra mắt. Đối với cộng đồng phát triển Java, Java 11 không chỉ là một phiên bản cập nhật thông thường mà còn đánh dấu một bước ngoặt quan trọng vì nhiều lý do.

Oracle đã thay đổi hoàn toàn mô hình hỗ trợ của họ và áp dụng một “release train” mô hình phát hành nhanh chóng, mang đến các bản cập nhật mới khoảng 6 tháng một lần. Quan trọng hơn, họ đã thay đổi cả mô hình cấp phép và hỗ trợ, điều này có nghĩa là nếu bạn tải xuống Oracle JDK 11, việc sử dụng nó cho mục đích thương mại sẽ yêu cầu trả phí.
Điều này có nghĩa là bạn sẽ phải trả tiền cho Java từ bây giờ ? KHÔNG. Không nhất thiết phải vậy, trừ khi bạn tải xuống Oracle JDK và sử dụng nó trong môi trường sản xuất.
(Lưu ý: IntelliJ IDEA 2018.2.4 Community Edition đã hỗ trợ Java 11.)
1. Tại sao Java 11 lại quan trọng?
Java 11 là bản phát hành hỗ trợ dài hạn (LTS) thứ hai sau Java 8. Kể từ Java 11, Oracle JDK không còn miễn phí cho mục đích thương mại nữa. Bạn có thể sử dụng nó trong giai đoạn phát triển, nhưng để triển khai thương mại, bạn cần mua giấy phép. Nếu không, bạn có thể nhận được hóa đơn từ Oracle bất cứ lúc nào!
Java 10 là bản Oracle JDK cuối cùng mà bạn có thể tải xuống miễn phí. Oracle cũng ngừng hỗ trợ miễn phí cho Java 8 từ tháng 1 năm 2019. Nếu muốn tiếp tục nhận hỗ trợ, bạn cần trả phí. Bạn vẫn có thể tiếp tục sử dụng Java 8, nhưng sẽ không nhận được bất kỳ bản vá lỗi/cập nhật bảo mật nào.
Oracle sẽ không cung cấp hỗ trợ dài hạn miễn phí (LTS) cho bất kỳ phiên bản Java nào kể từ Java 11.
Mặc dù Oracle JDK không còn miễn phí, bạn luôn có thể tải xuống các bản dựng OpenJDK từ Oracle hoặc các nhà cung cấp khác như AdoptOpenJDK, Azul, IBM, Red Hat, v.v. Theo quan điểm của tôi, trừ khi bạn tìm kiếm mức độ sử dụng cấp doanh nghiệp với ngân sách đủ để chi trả phí hỗ trợ, bạn hoàn toàn có thể sử dụng OpenJDK và nâng cấp khi cần thiết.
2. Nên tải xuống bản JDK nào và lợi ích của từng loại là gì?
Do Oracle đã tạo ra một “release train” với một phiên bản mới ra mắt sau mỗi sáu tháng, nếu bạn sử dụng bản OpenJDK miễn phí của Oracle, bạn sẽ cần cập nhật nó sáu tháng một lần. Điều này là do Oracle sẽ không cung cấp các bản cập nhật miễn phí khi phiên bản mới được phát hành.
Việc thích nghi với chu kỳ này có thể là một thách thức đối với các công ty. Để nhận được tất cả các cập nhật và hỗ trợ cho Java 11 đến năm 2026, bạn có thể trả phí hỗ trợ thương mại cho Oracle và chỉ cần di chuyển từ một phiên bản LTS sang phiên bản LTS tiếp theo.
Ví dụ, bạn có thể cân nhắc nâng cấp từ Java 11 lên Java 17 vào năm 2022. Tuy nhiên, nếu bạn chọn tiếp tục sử dụng phiên bản Java miễn phí ngay cả khi hết hỗ trợ, bạn sẽ không nhận được các bản cập nhật bảo mật và điều này có thể mở ra các lỗ hổng bảo mật.
Oracle sẽ không cung cấp hỗ trợ thương mại hoặc cập nhật cho Java 9 và Java 10. Bạn cần tìm các bản dựng thay thế khác để tiếp tục sử dụng chúng miễn phí.
Sau khi đã nắm rõ những “hành trang” mà Java 11 mang đến, chúng ta hãy cùng phân tích các tính năng quan trọng trong Java 11 dành cho các nhà phát triển. Chúng ta sẽ thảo luận một số JEP quan trọng. (Lưu ý: JavaFX sẽ có sẵn dưới dạng một module riêng biệt và không gắn liền với chu kỳ phát hành 6 tháng của Java JDK.)
3. Làm thế nào để tải xuống phiên bản Java 11 miễn phí?
Bạn có thể tải xuống phiên bản OpenJDK sẵn sàng cho sản xuất từ link này. Các tệp nhị phân ở định dạng .tar hoặc .zip, vì vậy bạn chỉ cần giải nén chúng và thiết lập các biến môi trường để sử dụng trình biên dịch java và các lệnh java.
4. Các tính năng của Java 11
Một số tính năng quan trọng của Java 11 bao gồm:
- Chạy tệp Java bằng một lệnh duy nhất
- Các phương thức tiện ích mới trong lớp
String - Cú pháp biến cục bộ cho tham số Lambda
- Kiểm soát truy cập dựa trên lồng ghép (Nested Based Access Control)
- JEP 321: HTTP Client
- Đọc/Ghi String với tệp
- JEP 328: Flight Recorder
Bây giờ, chúng ta hãy đi sâu vào các tính năng mới được giới thiệu trong Java 11 thông qua quy trình JEP.
4.1. Chạy tệp Java bằng một lệnh duy nhất
Một thay đổi lớn là bạn không cần biên dịch tệp mã nguồn Java bằng công cụ javac như trước. Bạn có thể chạy trực tiếp tệp bằng lệnh java và nó sẽ tự động biên dịch ngầm. Tính năng này thuộc JEP 330.
4.2. Các phương thức của Java String
Java 11 bổ sung một số phương thức tiện ích mới vào lớp String, giúp việc xử lý chuỗi trở nên dễ dàng và trực quan hơn.
isBlank() Phương thức instance này trả về một giá trị boolean. Các chuỗi rỗng và chuỗi chỉ chứa ký tự khoảng trắng được coi là “trống” (blank).
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
// Your code here!
System.out.println(" ".isBlank()); //true
String s = "Anupam";
System.out.println(s.isBlank()); //false
String s1 = "";
System.out.println(s1.isBlank()); //true
}
}
lines() – Phương thức này trả về một Stream<String> là một tập hợp tất cả các chuỗi con được phân tách theo dòng.
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
String str = "JD\\\\nJD\\\\nJD";
System.out.println(str);
System.out.println(str.lines().collect(Collectors.toList()));
}
}
Đầu ra của đoạn mã trên là:
JD
JD
JD
[JD, JD, JD]
**strip(), stripLeading(), stripTrailing()**strip() Loại bỏ khoảng trắng ở cả đầu và cuối chuỗi.
Chúng ta đã có trim(), vậy tại sao lại cần strip()? strip() là sự tiến hóa “nhận biết Unicode” của trim(). Khi trim() được giới thiệu, Unicode chưa phát triển mạnh mẽ. Bây giờ, strip() mới loại bỏ tất cả các loại khoảng trắng ở đầu và cuối (bạn có thể kiểm tra phương thức Character.isWhitespace(c) để biết một ký tự Unicode có phải là khoảng trắng hay không).
Ví dụ sử dụng ba phương thức trên:
public class Main {
public static void main(String[] args) throws Exception {
// Your code here!
String str = " JD ";
System.out.print("Start");
System.out.print(str.strip());
System.out.println("End");
System.out.print("Start");
System.out.print(str.stripLeading());
System.out.println("End");
System.out.print("Start");
System.out.print(str.stripTrailing());
System.out.println("End");
}
}
Đầu ra trong console từ đoạn mã trên là:
StartJDEnd
StartJD End
Start JDDEnd
repeat(int) Phương thức repeat chỉ đơn giản lặp lại chuỗi đó nhiều lần theo số lượng được chỉ định trong tham số dưới dạng một số nguyên.
public class Main {
public static void main(String[] args) throws Exception {
// Your code here!
String str = "=".repeat(2);
System.out.println(str); //prints ==
}
}
4.3. Cú pháp biến cục bộ cho tham số Lambda
JEP 323, Cú pháp biến cục bộ cho tham số Lambda (Local-Variable Syntax for Lambda Parameters), là tính năng ngôn ngữ duy nhất được phát hành trong Java 11. Trong Java 10, Suy luận kiểu biến cục bộ (Local Variable Type Inference) đã được giới thiệu. Do đó, chúng ta có thể suy luận kiểu của biến từ vế phải, ví dụ: var list = new ArrayList<String>();.
JEP 323 cho phép sử dụng var để khai báo các tham số hình thức của một biểu thức lambda được suy luận kiểu ngầm. Bây giờ chúng ta có thể định nghĩa:
(var s1, var s2) -> s1 + s2
Điều này thực tế đã có thể thực hiện trong Java 8 nhưng bị loại bỏ trong Java 10. Giờ đây, nó đã trở lại trong Java 11 để giữ mọi thứ nhất quán.
Nhưng tại sao chúng ta cần điều này khi chúng ta có thể chỉ bỏ qua kiểu trong lambda? Nếu bạn cần áp dụng một annotation như @Nullable, bạn không thể làm điều đó mà không định nghĩa kiểu.
Giới hạn của tính năng này: Bạn phải chỉ định kiểu var trên tất cả các tham số hoặc không có tham số nào. Những trường hợp như sau không được phép:
(var s1, s2) -> s1 + s2 // không được phép bỏ qua kiểu
(var s1, String y) -> s1 + y // không được phép trộn kiểu
var s1 -> s1 // không được phép. Cần dấu ngoặc đơn nếu bạn sử dụng var trong lambda.
4.4. Kiểm soát truy cập dựa trên lồng ghép (Nested Based Access Control)
Trước Java 11, điều này đã có thể xảy ra:
public class Main {
public void myPublic() {
}
private void myPrivate() {
}
class Nested {
public void nestedPublic() {
myPrivate();
}
}
}
Phương thức private của lớp chính có thể được truy cập từ lớp lồng ghép bên trên theo cách này. Nhưng nếu chúng ta sử dụng Java Reflection, nó sẽ gây ra một IllegalStateException.
Method method = ob.getClass().getDeclaredMethod("myPrivate");
method.invoke(ob);
Kiểm soát truy cập lồng ghép của Java 11 giải quyết mối lo ngại này trong reflection. Lớp java.lang.Class giới thiệu ba phương thức mới trong Reflection API: getNestHost(), getNestMembers(), và isNestmateOf().
4.5) JEP 309: Hằng số tệp Class động (Dynamic Class-File Constants)
Định dạng tệp class của Java giờ đây mở rộng hỗ trợ một dạng constant pool mới, CONSTANT_Dynamic. Mục tiêu của JEP này là giảm chi phí và sự gián đoạn trong việc phát triển các dạng ràng buộc tệp class có thể hiện thực hóa mới, bằng cách tạo ra một dạng constant-pool mới duy nhất có thể được tham số hóa với hành vi do người dùng cung cấp. Điều này giúp tăng cường hiệu suất.
4.6. JEP 318: Epsilon: Bộ thu gom rác No-Op (No-Op Garbage Collector)
Không giống như các bộ thu gom rác (GC) khác của JVM chịu trách nhiệm cấp phát bộ nhớ và giải phóng nó, Epsilon chỉ cấp phát bộ nhớ. Nó cấp phát bộ nhớ cho các mục đích sau:
- Kiểm thử hiệu suất.
- Kiểm thử áp lực bộ nhớ.
- Kiểm thử giao diện VM.
- Các công việc có vòng đời cực ngắn.
- Cải thiện độ trễ tối thiểu (last-drop latency).
- Cải thiện thông lượng tối thiểu (last-drop throughput).
Tuy nhiên, Epsilon chỉ tốt cho môi trường kiểm thử. Nó sẽ dẫn đến OutOfMemoryError trong môi trường sản xuất và làm sập ứng dụng. Lợi ích của Epsilon là không có chi phí dọn dẹp bộ nhớ. Do đó, nó sẽ cho kết quả kiểm thử hiệu suất chính xác và chúng ta không còn cần GC để ngăn chặn nó. (Lưu ý: Đây là một tính năng thử nghiệm.)
4.7. JEP 320: Xóa các mô-đun Java EE và CORBA
Các mô-đun này đã bị đánh dấu là không dùng nữa (deprecated) trong Java 9. Giờ đây, chúng đã bị loại bỏ hoàn toàn trong Java 11. Các gói sau đã bị xóa: java.xml.ws, java.xml.bind, java.activation, java.xml.ws.annotation, java.corba, java.transaction, java.se.ee, jdk.xml.ws, jdk.xml.bind.
4.8. JEP 328: Flight Recorder (JFR)
Flight Recorder, trước đây là một tiện ích bổ sung thương mại trong Oracle JDK, giờ đây đã được mã nguồn mở vì bản thân Oracle JDK không còn miễn phí nữa. JFR là một công cụ phân tích được sử dụng để thu thập dữ liệu chẩn đoán và phân tích từ một ứng dụng Java đang chạy. Chi phí hiệu suất của nó không đáng kể, thường dưới 1%. Do đó, bạn có thể sử dụng nó trong các ứng dụng sản xuất.
4.9. JEP 321: HTTP Client
Java 11 tiêu chuẩn hóa API Http Client. API mới hỗ trợ cả HTTP/1.1 và HTTP/2. Nó được thiết kế để cải thiện hiệu suất tổng thể của việc gửi yêu cầu bởi client và nhận phản hồi từ server. Nó cũng hỗ trợ nguyên bản WebSockets.
4.10. Đọc/Ghi String với tệp
Java 11 nỗ lực làm cho việc đọc và ghi String trở nên tiện lợi. Nó đã giới thiệu các phương thức sau để đọc và ghi từ/vào tệp:
readString()writeString()
Đoạn mã sau minh họa một ví dụ về điều này:
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) throws Exception {
Path path = Files.writeString(Files.createTempFile("test", ".txt"), "This was posted on JD");
System.out.println(path);
String s = Files.readString(path);
System.out.println(s); //This was posted on JD
}
}
4.11. JEP 329: Thuật toán mật mã ChaCha20 và Poly1305
Java 11 cung cấp các triển khai thuật toán mã hóa ChaCha20 và ChaCha20-Poly1305. Các thuật toán này sẽ được triển khai trong nhà cung cấp SunJCE.
4.12. JEP 315: Cải thiện Intrinsics cho Aarch64
Cải thiện các intrinsics chuỗi và mảng hiện có, và triển khai các intrinsics mới cho các hàm java.lang.Math như sin, cos, và log trên bộ xử lý AArch64.
4.13. JEP 333: ZGC: Bộ thu gom rác có độ trễ thấp, có khả năng mở rộng (Thử nghiệm)
Java 11 đã giới thiệu một GC có độ trễ thấp. Đây là một tính năng thử nghiệm. Thật tốt khi thấy Oracle đang chú trọng đến các bộ thu gom rác.
4.14. JEP 335: Loại bỏ Nashorn JavaScript Engine
Công cụ và API script JavaScript Nashorn đã bị đánh dấu là deprecated, điều này đồng nghĩa với việc chúng sẽ bị loại bỏ trong các bản phát hành Java tiếp theo
5. Kết luận
Java 11 rõ ràng là một phiên bản then chốt, mang theo những thay đổi lớn về cách chúng ta tiếp cận và sử dụng JDK, đặc biệt là liên quan đến các mô hình cấp phép. Nắm vững sự khác biệt giữa Oracle JDK trả phí và OpenJDK miễn phí là điều cực kỳ quan trọng đối với mọi nhà phát triển và tổ chức. Bên cạnh đó, các tính năng mới như các phương thức tiện ích của String, var trong lambda, hay HTTP Client API chuẩn hóa sẽ nâng cao năng suất và khả năng viết mã của bạn.