Cuối cùng thì JDK 12, một phần trong chu kỳ phát hành sáu tháng, đã ra mắt. Nó được phát hành sau phiên bản Java LTS gần nhất là Java 11. Trước đây, chúng ta đã thảo luận khá chi tiết về các tính năng của Java 11.
Hôm nay, chúng ta sẽ cùng tìm hiểu các tính năng mới của Java 12 và xem nó mang đến điều gì cho các lập trình viên. Java 12 được ra mắt vào ngày 19 tháng 3 năm 2019. Đây là một phiên bản Non-LTS, vì vậy nó sẽ không có hỗ trợ dài hạn.
Một số tính năng quan trọng của Java 12 bao gồm;
- Thay đổi trong JVM – JEP 189, JEP 346, JEP 344, và JEP 230.
- Switch Expressions
- Phương thức File.mismatch()
- Compact Number Formatting
- Teeing Collectors trong Stream API
- Các phương thức mới trong Java Strings – indent(), transform(), describeConstable(), và resolveConstantDesc().
- JEP 334: JVM Constants API
- JEP 305: Pattern Matching cho instanceof
- Raw String Literals đã bị loại bỏ khỏi JDK 12.
Tính năng mới của Java 12
Thay đổi trong JVM
1. JEP 189: Bộ thu gom rác (Garbage Collector) với thời gian tạm dừng thấp (Experimental)
RedHat đã khởi xướng Shenandoah Garbage Collector nhằm giảm thời gian tạm dừng của GC. Ý tưởng là cho phép GC chạy song song với các Java thread đang hoạt động. Mục tiêu của nó là mang lại những khoảng tạm dừng ngắn, ổn định và có thể dự đoán được, không phụ thuộc vào kích thước heap. Vì vậy, dù heap size là 15 MB hay 15 GB cũng không quan trọng. Đây là một tính năng thử nghiệm (experimental) trong Java 12.
2. JEP 346 – Trả lại ngay bộ nhớ đã cấp phát nhưng không sử dụng từ G1
Bắt đầu từ Java 12, G1 sẽ kiểm tra bộ nhớ Java Heap trong thời gian ứng dụng không hoạt động và trả lại phần bộ nhớ không sử dụng cho hệ điều hành. Đây là một biện pháp chủ động để tiết kiệm và tận dụng bộ nhớ trống.
3. JEP 344: Các bộ sưu tập hỗn hợp (Mixed Collections) có thể hủy trong G1
Những cải tiến về hiệu suất của G1 bao gồm khả năng hủy bỏ (abort) các mixed collections nếu chúng có khả năng vượt quá ngưỡng thời gian tạm dừng đã định. Điều này được thực hiện bằng cách chia tập hợp bộ sưu tập hỗn hợp thành bắt buộc (mandatory) và tùy chọn (optional). Nhờ vậy, G1 collector có thể ưu tiên thu gom tập bắt buộc trước để đáp ứng mục tiêu về thời gian tạm dừng.
4. JEP 230 và JEP 344
Microbenchmark Suite, tính năng JEP 230 bổ sung một bộ microbenchmark cơ bản vào mã nguồn JDK. Điều này giúp các lập trình viên dễ dàng chạy các microbenchmark có sẵn và tạo các benchmark mới. One AArch64 Port, Not Two, JEP 344 loại bỏ tất cả các mã nguồn liên quan đến arm64 port, trong khi vẫn giữ lại ARM 32-bit port và aarch64 64-bit port. Điều này cho phép các nhà đóng góp tập trung nỗ lực vào một triển khai ARM 64-bit duy nhất.
5. JEP 341 – Default CDS Archives
Tính năng này cải tiến quy trình build của JDK để tạo ra class data-sharing (CDS) archive, sử dụng danh sách class mặc định, trên các nền tảng 64-bit. Mục tiêu là để cải thiện thời gian khởi động. Từ Java 12, CDS được bật mặc định. Nếu muốn chạy chương trình với CDS bị tắt, hãy thực hiện như sau:
java -Xshare:off HelloWorld.java
Bây giờ, điều này sẽ làm chậm thời gian khởi động của chương trình.
Thay đổi và tính năng ngôn ngữ
Java 12 đã giới thiệu nhiều tính năng ngôn ngữ mới. Hãy cùng xem một vài trong số đó kèm theo cách triển khai.
1. Switch Expressions (Preview)
Java 12 đã nâng cấp Switch expressions cho Pattern matching. Được giới thiệu trong JEP 325, như một tính năng ngôn ngữ ở dạng preview, cú pháp mới là L ->
. Sau đây là một số điểm cần lưu ý về Switch Expressions:
- Cú pháp mới loại bỏ nhu cầu phải dùng break để ngăn fallthroughs.
- Switch Expressions không còn fallthrough nữa.
- Chúng ta có thể định nghĩa nhiều hằng số trong cùng một label.
default
case giờ đây là bắt buộc trong Switch Expressions.break
được sử dụng trong Switch Expressions để trả về giá trị trực tiếp từ một case.
Câu lệnh switch truyền thống:
String result = "";
switch (day) {
case "M":
case "W":
case "F": {
result = "MWF";
break;
}
case "T":
case "TH":
case "S": {
result = "TTS";
break;
}
};
System.out.println("Old Switch Result:");
System.out.println(result);
Với Switch expression (biểu thức chuyển đổi) mới, chúng ta không cần phải đặt break ở mọi nơi, nhờ đó tránh được các lỗi logic!
String result = switch (day) {
case "M", "W", "F" -> "MWF";
case "T", "TH", "S" -> "TTS";
default -> {
if(day.isEmpty())
break "Please insert a valid day.";
else
break "Looks like a Sunday.";
}
};
System.out.println(result);
Hãy chạy chương trình dưới đây có chứa biểu thức chuyển đổi mới bằng JDK 12.
public class SwitchExpressions {
public static void main(String[] args)
{
System.out.println("New Switch Expression result:");
executeNewSwitchExpression("M");
executeNewSwitchExpression("TH");
executeNewSwitchExpression("");
executeNewSwitchExpression("SUN");
}
public static void executeNewSwitchExpression(String day){
String result = switch (day) {
case "M", "W", "F" -> "MWF";
case "T", "TH", "S" -> "TTS";
default -> {
if(day.isEmpty())
break "Please insert a valid day.";
else
break "Looks like a Sunday.";
}
};
System.out.println(result);
}
}
Vì đây là một tính năng preview, vui lòng đảm bảo rằng bạn đã chọn trình độ ngôn ngữ là Java 12 preview. Để biên dịch đoạn code trên, hãy chạy lệnh sau:
javac -Xlint:preview --enable-preview -source 12 src/main/java/SwitchExpressions.java
Sau khi chạy chương trình đã được biên dịch, chúng ta sẽ nhận được kết quả sau trong console.
Chuyển đổi biểu thức là một tính năng ngôn ngữ ở dạng preview. Điều này có nghĩa là mặc dù nó đã hoàn chỉnh, nhưng chưa chắc sẽ được xác nhận trong các phiên bản Java phát hành trong tương lai.
2. Phương thức File.mismatch
Java 12 đã bổ sung phương thức sau để so sánh hai file:
public static long mismatch(Path path, Path path2) throws IOException
Phương thức này trả về vị trí của sự khác biệt đầu tiên, hoặc -1L nếu không có sự khác biệt. Hai file có thể khác nhau trong các trường hợp sau:
- Nếu các byte không giống hệt nhau. Trong trường hợp này, vị trí của byte khác nhau đầu tiên sẽ được trả về.
- Nếu kích thước file không giống nhau. Trong trường hợp này, kích thước của file nhỏ hơn sẽ được trả về.
Ví dụ code snippet từ IntelliJ IDEA được đưa ra dưới đây:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FileMismatchExample {
public static void main(String[] args) throws IOException {
Path filePath1 = Files.createTempFile("file1", ".txt");
Path filePath2 = Files.createTempFile("file2", ".txt");
Files.writeString(filePath1,"JournalDev Test String");
Files.writeString(filePath2,"JournalDev Test String");
long mismatch = Files.mismatch(filePath1, filePath2);
System.out.println("File Mismatch position... It returns -1 if there is no mismatch");
System.out.println("Mismatch position in file1 and file2 is >>>>");
System.out.println(mismatch);
filePath1.toFile().deleteOnExit();
filePath2.toFile().deleteOnExit();
System.out.println();
Path filePath3 = Files.createTempFile("file3", ".txt");
Path filePath4 = Files.createTempFile("file4", ".txt");
Files.writeString(filePath3,"JournalDev Test String");
Files.writeString(filePath4,"JournalDev.com Test String");
long mismatch2 = Files.mismatch(filePath3, filePath4);
System.out.println("Mismatch position in file3 and file4 is >>>>");
System.out.println(mismatch2);
filePath3.toFile().deleteOnExit();
filePath4.toFile().deleteOnExit();
}
}
Kết quả khi chương trình Java trên được biên dịch và chạy là:
3. Định dạng số gọn nhẹ
import java.text.NumberFormat;
import java.util.Locale;
public class CompactNumberFormatting {
public static void main(String[] args)
{
System.out.println("Compact Formatting is:");
NumberFormat upvotes = NumberFormat
.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.SHORT);
upvotes.setMaximumFractionDigits(1);
System.out.println(upvotes.format(2592) + " upvotes");
NumberFormat upvotes2 = NumberFormat
.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.LONG);
upvotes2.setMaximumFractionDigits(2);
System.out.println(upvotes2.format(2011) + " upvotes");
}
}
4. Teeing Collectors
Teeing Collector là một tiện ích collector mới được giới thiệu trong Streams API. Collector này có ba tham số – hai collectors và một Bi-function. Tất cả các giá trị đầu vào sẽ được truyền cho từng collector, và kết quả cuối cùng sẽ có sẵn trong Bi-function.
double mean = Stream.of(1, 2, 3, 4, 5)
.collect(Collectors.teeing(
summingDouble(i -> i),
counting(),
(sum, n) -> sum / n));
System.out.println(mean);
Kết quả là 3.0.
5. Các phương thức mới của Java Strings
Trong Java 12 đã giới thiệu 4 phương thức mới như sau:
- indent(int n)
- transform(Function f)
- Optional describeConstable()
- String resolveConstantDesc(MethodHandles.Lookup lookup)
Để tìm hiểu chi tiết về các phương thức trên và cách triển khai chúng, bạn có thể tham khảo bài hướng dẫn Java 12 String Methods của chúng tôi.
6. JEP 334: API hằng số của JVM)
Một package mới java.lang.constant
được giới thiệu cùng với JEP này. Tính năng này không quá hữu ích đối với các lập trình viên không sử dụng constant pool.
7. JEP 305: Pattern Matching cho instanceof (Preview)
Lại một tính năng ngôn ngữ dạng Preview nữa! Cách cũ để ép kiểu (typecast) từ một kiểu sang kiểu khác là:
if (obj instanceof String) {
String s = (String) obj;
// use s in your code from here
}
Cách mới là:
if (obj instanceof String s) {
// can use s directly here
}
Điều này giúp chúng ta loại bỏ một số thao tác ép kiểu không cần thiết.
Raw String Literals đã bị loại bỏ khỏi JDK 12.
Như vậy, bài viết về các tính năng của Java 12 xin được kết thúc tại đây.