簡介
本次的Jdk14版本將帶來16個增強方案
除此之外,Jdk14版本修復了共1986項問題,其中大部分由Oracle工作人員完成
增強
- JEP 305 - Pattern Matching for instanceof (Preview)
- JEP 343 - Packaging Tool (Incubator)
- JEP 345 - NUMA-Aware Memory Allocation for G1
- JEP 349 - JFR Event Streaming
- JEP 352 - Non-Volatile Mapped Byte Buffers
- JEP 358 - Helpful NullPointerExceptions:
- JEP 359 - Records (Preview)
- JEP 361 - Switch Expressions
- JEP 362 - Deprecate the Solaris and SPARC Ports
- JEP 363 - Remove the Concurrent Mark Sweep (CMS) Garbage Collector
- JEP 364 - ZGC on macOS
- JEP 365 - ZGC on Windows
- JEP 366 - Deprecate the ParallelScavenge + SerialOld GC Combination
- JEP 367 - Remove the Pack200 Tools and API
- JEP 368 - Text Blocks (Second Preview)
- JEP 370 - Foreign-Memory Access API (Incubator)
環境
- Jdk14:https://www.oracle.com
- Idea2020.1:https://www.jetbrains.com
食用
JEP 305:instanceof的模式匹配:通過消除對通用樣板代碼的需求,提高了開發人員的生產率,並允許使用更簡潔的類型安全的代碼
在Jdk之前的版本中,使用instanceof模式匹配的時候需要手動進行強制轉換成需要的類型。在該版本中可以直接在後面跟上變量名,接下來不用強轉就能直接使用該變量
Object obj = "hello 14";
// Jdk之前版本
if (obj instanceof String) {
String str = (String) obj;
System.out.println("str length:" + str.length());
} else {
System.out.println("obj not string.");
}
// Jdk14版本
if (obj instanceof String str) {
System.out.println("str length:" + str.length());
} else {
System.out.println("obj not string.");
}
JEP 343:打包工具:此孵化器工具爲開發人員提供了一種打包Java應用程序的方式,以便以平臺特定的格式進行分發
這些格式包括Windows上的msi和exe,MacOS上的pkg和dmg,以及Linux上的deb和rpm
JEP 345:G1的NUMA-Aware內存分配:此功能提高了非均勻內存訪問(NUMA)系統上G1垃圾收集器的整體性能
NUMA技術:https://www.ibm.com/developerworks/cn/linux/l-numa/index.html
JEP 349:JFR事件流:此功能公開了JDK Flight Recorder(JFR)數據以進行連續監視,這將簡化各種工具和應用程序對JFR數據的訪問
HotSpot VM使用JFR發出500多個數據點,除了解析日誌文件外,大多數其他方法無法使用。如果要使用數據,用戶必須開始記錄,停止記錄,將內容轉儲到磁盤,然後解析記錄文件。這對於應用程序概要分析非常有效,其中通常一次記錄至少一分鐘的數據,但不適用於監視目的。而在新特性中可以公開JFR發出的數據,用於持續監控
JEP 352:非易失性映射字節緩衝區:使用非易失性存儲器時,此功能爲JDK添加了文件映射模式
對FileChannel API進行了擴展,允許創建MappedByteBuffer實例。非易失性內存能夠持久化數據,因此可以利用該特性來改進性能
JEP 358:實用的NullPointerExceptions:通過精確描述哪個變量爲null以及其他有用信息,提高了 NullPointerExceptions的可用性。這將提高開發人員的生產率,並提高許多開發和調試工具的質量
目前該特性需要使用-XX:+ShowCodeDetailsInExceptionMessages參數開啓
String str = null;
System.out.println(str.length());
/**
* Jdk之前版本異常輸出:
* Exception in thread "main" java.lang.NullPointerException
* at DemoNull.main(DemoNull.java:9)
*/
/**
* Jdk14版本異常輸出:
* Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is null
* at DemoNull.main(DemoNull.java:9)
*/
JEP 359:Records:此預覽功能提供了一種緊湊的語法,用於聲明保存淺層不變數據的類。從表面上看,此功能大大減少了此類中的樣板代碼,但最終目的是更好地允許將數據建模爲數據
在之前的Jdk版本中,如果我們要申明一個final實體類,需要手動寫構造器、getter、equals、hashCode、toString等方法。而現在,只需要使用record關鍵字,一行代碼即可搞定,申明之後將自動獲得一個構造器、getter、equals、hashCode、toString方法。在record申明的類中也可以定義其他構造器、方法、靜態方法和靜態屬性。record申明的類不能再用abstract修飾。record申明的類不能繼承其他的類。
/**
* @author liujiazhong
*/
public final class Order {
private final Long orderId;
private final String orderCode;
public Order(Long orderId, String orderCode) {
this.orderId = orderId;
this.orderCode = orderCode;
}
public Long getOrderId() {
return orderId;
}
public String getOrderCode() {
return orderCode;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Order)) return false;
Order order = (Order) o;
return Objects.equals(getOrderId(), order.getOrderId()) &&
Objects.equals(getOrderCode(), order.getOrderCode());
}
@Override
public int hashCode() {
return Objects.hash(getOrderId(), getOrderCode());
}
@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", orderCode='" + orderCode + '\'' +
'}';
}
}
/**
* @author liujiazhong
*/
public record RecordOrder(Long orderId, String orderCode) {
}
// 測試
Order order1 = new Order(1001L, "TEST1001");
RecordOrder order2 = new RecordOrder(1002L, "TEST1002");
System.out.println(order1);
System.out.println(order2);
System.out.println(order1.getOrderCode());
System.out.println(order2.orderCode());
// 結果
Order{orderId=1001, orderCode='TEST1001'}
RecordOrder[orderId=1002, orderCode=TEST1002]
TEST1001
TEST1002
// 可以定義其他信息
public record RecordOrder(Long orderId, String orderCode) {
public static final String TYPE = "online";
public RecordOrder() {
this(1003L, "TEST1003");
}
public static void printType() {
System.out.println(TYPE);
}
public void printOrderCode() {
System.out.println(orderCode);
}
}
JEP 361:Switch表達式:它允許將switch用作語句或表達式,簡化了日常的編碼,這是JDK 12和JDK 13中的預覽功能
String str = "A";
// Jdk之前的版本
switch (str) {
case "A":
System.out.println("A");break;
case "B":
System.out.println("B");break;
default:
System.out.println("default");
}
// Jdk12之後
switch (str) {
case "A", "C" -> System.out.println("A || C");
case "B" -> System.out.println("B");
default -> System.out.println("default");
}
// yield用於返回值
int score = switch (str) {
case "A" -> 90;
case "B" -> 80;
default -> {
System.out.println("default");
yield 70;
}
};
System.out.println(score);
JEP 362:棄用Solaris和SPARC端口:在將來的發行版中將其刪除
放棄對這些端口的支持將使OpenJDK社區中的貢獻者能夠加速新功能的開發,這些新功能將推動平臺向前發展
JEP 363:刪除併發標記掃描(CMS)垃圾回收器
CMS垃圾收集器在兩年前已過時,並且自JDK 6起已成爲CMS的後繼產品的G1已成爲默認GC,並且已經在許多情況下大規模使用。我們還看到引入了兩個新的收集器,ZGC(Jdk11)和Shenandoah(Open Jdk12),同時對G1進行了許多改進 。CMS存在幾個弊端,比如會產生內存碎片,併發清理後導致用戶線程可用的空間不足,因爲是併發清理,所以對CPU資源非常敏感,而且無法處理浮動垃圾
詳細信息:https://openjdk.java.net/jeps/363
/**
* 在Jdk14中通過-XX:+UseConcMarkSweepGC選項嘗試使用CMS的話會得到下面的警告信息
* Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; support was removed in 14.0
*/
List<String> list = new ArrayList<>();
while (true) {
list.add("a");
}
JEP 364,JEP 365:ZGC on macOS and Windows:儘管大多數需要ZGC的用戶也需要基於Linux的環境的可伸縮性,但是在Windows和macOS中也經常需要部署和測試它。還有某些桌面應用程序將從ZGC功能中受益。因此,ZGC功能已移植到Windows和macOS
ZGC與Shenandoah目標非常相似,在儘可能對吞吐量影響不大的前提下,實現在任意堆內存大小下都可以把停頓時間限制在10毫秒以內。ZGC收集器是一款基於Region內存佈局的,(暫時)不設分代,使用了讀屏障、染色指針和內存多重映射等技術來實現可併發標記-壓縮算法,首要目標是低延遲
詳細信息:https://openjdk.java.net/jeps/364
上圖引用自:The Z Garbage Collector - An Introduction
/**
* -XX:+UnlockExperimentalVMOptions -XX:+UseZGC
*/
List<String> list = new ArrayList<>();
while (true) {
list.add("a");
}
JEP 366:棄用ParallelScavenge + SerialOld GC組合,該組合很少使用,但需要大量維護工作
詳細信息:https://openjdk.java.net/jeps/366
/**
* 使用-XX:+UseParallelGC -XX:-UseParallelOldGC或者-XX:-UseParallelOldGC參數啓用組合後提示以下信息
* Java HotSpot(TM) 64-Bit Server VM warning: Option UseParallelOldGC was deprecated in version 14.0 and will likely be removed in a future release.
*/
public static void main(String[] args) {
List<String> list = new ArrayList<>();
while (true) {
list.add("a");
}
}
JEP 367:刪除Pack200工具和API:將刪除java.util.jar軟件包中的pack200和unpack200工具以及Pack200 API。這些工具和API 已在Java SE 11中棄用
刪除原因:https://openjdk.java.net/jeps/367
JEP 368:文本塊:在Java 首次將文本塊作爲預覽功能(JEP 355)引入時,收到反饋後,添加了兩個新的轉義序列。該功能增強了Java程序中用非Java語言編寫代碼的字符串的可讀性
// Jdk之前的版本
String sql1 = "select\n" +
"\t*\n" +
"from\n" +
"\tord_order_item ooi\n" +
"left join ord_order oo on\n" +
"\tooi.order_id = oo.id\n" +
"where\n" +
"\too.order_code = 'TEST1001'\n" +
"order by\n" +
"\too.id desc";
// 三引號表示文本塊
String sql2 = """
select
*
from
ord_order_item ooi
left join ord_order oo on
ooi.order_id = oo.id
where
oo.order_code = 'TEST1001'
order by
oo.id desc
""";
// 新增“\s”表示空格,“\”表示去除換行
String sql3 = """
select
*
from
ord_order_item ooi
left join ord_order oo on
ooi.order_id = oo.id
where
oo.order_code = 'TEST1001'
order by\s\
oo.id desc
""";
System.out.println(sql1);
System.out.println(sql2);
System.out.println(sql3);
JEP 370:外部存儲器訪問API:此孵化器模塊引入了一個API,以允許Java程序安全有效地訪問Java堆之外的外部存儲器
詳細信息:https://openjdk.java.net/jeps/370
補充
鏈接
Java:https://www.oracle.com/java/
Jdk14:https://www.oracle.com/java/technologies/javase-jdk14-downloads.html
The Arrival of Java 14:https://blogs.oracle.com/java-platform-group/the-arrival-of-java-14