JDK 13新特性介紹
JDK 13新特性介紹
1.1 JDK 各版本主要特性回顧
JDK Version 1.0
1996-01-23 Oak(橡樹)
- 初代版本,偉大的一個里程碑,但是是純解釋執行,使用外掛JIT,效能比較差,執行速度慢。
JDK Version 1.1
1997-02-19
- JDBC(Java DataBase Connectivity);
- 支援內部類;
- RMI(Remote Method Invocation) ;
- 反射;
- Java Bean;
JDK Version 1.2
- 集合框架;
- JIT(Just In Time)編譯器;
- 對打包的Java檔案進行數字簽名;
- JFC(Java Foundation Classes), 包括Swing 1.0, 拖放和Java2D類庫;
- Java外掛;
- JDBC中引入可滾動結果集,BLOB,CLOB,批量更新和使用者自定義型別;
- Applet中新增聲音支援.
- 同時,Sun釋出了 JSP/Servlet、EJB規範,以及將Java分成了 J2EE、J2SE和J2ME。 這表明了 Java開始向企業、桌面
- 應用和移動裝置應用3大領域挺進。
JDK Version 1.3
2000-05-08 Kestrel(紅隼)
- Java Sound API;
- jar檔案索引;
- 對Java的各個方面都做了大量優化和增強;
JDK Version 1.4
2004-02-06 Merlin(隼)
- XML處理;
- Java列印服務;
- Logging API;
- Java Web Start;
- JDBC 3.0 API;
- 斷言;
- Preferences API;
- 鏈式異常處理;
- 支援IPV6;
- 支援正則表示式;
- 引入Imgae I/O API.
JAVA 5
2004-09-30 Tiger(老虎)
- 泛型;
- 增強迴圈,可以使用迭代方式;
- 自動裝箱與自動拆箱;
- 型別安全的列舉;
- 可變引數;
- 靜態引入;
- 元資料(註解);
- Instrumentation;
JAVA 6
2006-12-11 Mustang(野馬)
- 支援指令碼語言;
- JDBC 4.0API;
- Java Compiler API;
- 可插拔註解;
- 增加對Native PKI(Public Key Infrastructure), Java GSS(Generic Security Service),Kerberos和LDAP(Lightweight Directory Access Protocol)支援;
- 繼承Web Services;
JAVA 7
2011-07-28 Dolphin(海豚)
- switch語句塊中允許以字串作為分支條件;
- 在建立泛型物件時應用型別推斷;
- 在一個語句塊中捕獲多種異常;
- 支援動態語言;
- 支援try-with-resources(在一個語句塊中捕獲多種異常);
- 引入Java NIO.2開發包;
- 數值型別可以用二進位制字串表示,並且可以在字串表示中新增下劃線;
鑽石型語法(在建立泛型物件時應用型別推斷); - null值得自動處理;
JAVA 8
2014-03-18
- Lambda 表示式 − Lambda允許把函式作為一個方法的引數(函式作為引數傳遞進方法中。
- 方法引用 − 方法引用提供了非常有用的語法,可以直接引用已有Java類或物件(例項)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗餘程式碼。
- 預設方法 − 預設方法就是一個在接口裡面有了一個實現的方法。
- 新工具 − 新的編譯工具,如:Nashorn引擎 jjs、 類依賴分析器jdeps。
- Stream API −新新增的Stream API(java.util.stream) 把真正的函數語言程式設計風格引入到Java中。
- Date Time API − 加強對日期與時間的處理。
- Optional 類 − Optional 類已經成為 Java 8 類庫的一部分,用來解決空指標異常。
- Nashorn, JavaScript 引擎 − Java 8提供了一個新的Nashorn javascript引擎,它允許我們在JVM上執行特定的javascript應用。
JAVA 9
2017-09-22
- 模組系統:模組是一個包的容器,Java 9 最大的變化之一是引入了模組系統(Jigsaw 專案)。
REPL (JShell):互動式程式設計環境。 - HTTP 2 客戶端:HTTP/2標準是HTTP協議的最新版本,新的 HTTPClient API 支援 WebSocket 和 HTTP2 流以及伺服器推送特性。
- 改進的 Javadoc:Javadoc 現在支援在 API 文件中的進行搜尋。另外,Javadoc 的輸出現在符合相容 HTML5 標準。
- 多版本相容 JAR 包:多版本相容 JAR 功能能讓你建立僅在特定版本的 Java 環境中執行庫程式時選擇使用的 class 版本。
- 集合工廠方法:List,Set 和 Map 介面中,新的靜態工廠方法可以建立這些集合的不可變例項。
- 私有介面方法:在介面中使用private私有方法。我們可以使用 private 訪問修飾符在介面中編寫私有方法。
- 程序 API: 改進的 API 來控制和管理作業系統程序。引進 java.lang.ProcessHandle 及其巢狀介面 Info 來讓開發者逃離時常因為要獲取一個本地程序的 PID 而不得不使用原生代碼的窘境。
- 改進的 Stream API:改進的 Stream API 添加了一些便利的方法,使流處理更容易,並使用收集器編寫複雜的查詢。
- 改進 try-with-resources:如果你已經有一個資源是 final 或等效於 final 變數,您可以在 try-with-resources 語句中使用該變數,而無需在 try-with-resources 語句中宣告一個新變數。
- 改進的棄用註解 @Deprecated:註解 @Deprecated 可以標記 Java API 狀態,可以表示被標記的 API 將會被移除,或者已經破壞。
- 改進鑽石操作符(Diamond Operator) :匿名類可以使用鑽石操作符(Diamond Operator)。
改進 Optional 類:java.util.Optional 添加了很多新的有用方法,Optional 可以直接轉為 stream。 - 多解析度影象 API:定義多解析度影象API,開發者可以很容易的操作和展示不同解析度的影象了。
改進的 CompletableFuture API : CompletableFuture 類的非同步機制可以在 ProcessHandle.onExit 方法退出時執行操作。 - 輕量級的 JSON API:內建了一個輕量級的JSON API
- 響應式流(Reactive Streams) API: Java 9中引入了新的響應式流 API 來支援 Java 9 中的響應式程式設計。
JAVA 10
2018-03-21
根據官網的公開資料,共有12個重要特性,如下:
- JEP286,var 區域性變數型別推斷。
- JEP296,將原來用 Mercurial 管理的眾多 JDK 倉庫程式碼,合併到一個倉庫中,簡化開發和管理過程
- JEP304,統一的垃圾回收介面。
- JEP307,G1 垃圾回收器的並行完整垃圾回收,實現並行性來改善最壞情況下的延遲。
- JEP310,應用程式類資料 (AppCDS) 共享,通過跨程序共享通用類元資料來減少記憶體佔用空間,和減少啟動時間。
- JEP312,ThreadLocal 握手互動。在不進入到全域性 JVM 安全點 (Safepoint) 的情況下,對執行緒執行回撥。優化可以只停止單個執行緒,而不是停全部執行緒或一個都不停。
- JEP313,移除 JDK 中附帶的 javah 工具。可以使用 javac -h 代替。
- JEP314,使用附加的 Unicode 語言標記擴充套件。
- JEP317,能將堆記憶體佔用分配給使用者指定的備用記憶體裝置。
- JEP317,使用 Graal 基於 Java 的編譯器,可以預先把 Java 程式碼編譯成原生代碼來提升效能。
- JEP318,在 OpenJDK 中提供一組預設的根證書頒發機構證書。開源目前 Oracle 提供的的 Java SE 的根證書,這樣 OpenJDK 對開發人員使用起來更方便。
- JEP322,基於時間定義的釋出版本,即上述提到的釋出週期。版本號為$FEATURE.$INTERIM.$UPDATE.$PATCH,分j別是大版本,中間版本,升級包和補丁版本。
JAVA 11
2018-09-25
翻譯後的新特性有:
- 181:Nest-Based訪問控制
- 309:動態類檔案常量
- 315:改善Aarch64 intrinsic
- 318:無操作垃圾收集器
- 320:消除Java EE和CORBA模組
- 321:HTTP客戶端(標準)
- 323:區域性變數的語法λ引數
- 324:Curve25519和Curve448關鍵協議
- 327:Unicode 10
- 328:飛行記錄器
- 329:ChaCha20和Poly1305加密演算法
- 330:發射一列縱隊原始碼程式
- 331:低開銷堆分析
- 332:傳輸層安全性(Transport Layer Security,TLS)1.3
- 333:動作:一個可伸縮的低延遲垃圾收集器 (實驗)
- 335:反對Nashorn JavaScript引擎
- 336:反對Pack200工具和API
JAVA 12
2018-09-25
翻譯後的新特性有:
- 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental) :新增一個名為 Shenandoah 的垃圾回收器,它通過在 Java 執行緒執行的同時進行疏散 (evacuation) 工作來減少停頓時間。
- 230: Microbenchmark Suite:新增一套微基準測試,使開發者能夠基於現有的 Java Microbenchmark Harness(JMH)輕鬆測試 JDK 的效能,並建立新的基準測試。
- 325: Switch Expressions (Preview) :對 switch 語句進行擴充套件,使其可以用作語句或表示式,簡化日常程式碼。
- 334: JVM Constants API :引入一個 API 來對關鍵類檔案 (key class-file) 和執行時工件的名義描述(nominal descriptions)進行建模,特別是那些可從常量池載入的常量。
- 340: One AArch64 Port, Not Two :刪除與 arm64 埠相關的所有原始碼,保留 32 位 ARM 移植和 64 位 aarch64 移植。
- 341: Default CDS Archives :預設生成類資料共享(CDS)存檔。
- 344: Abortable Mixed Collections for G1 :當 G1 垃圾回收器的回收超過暫停目標,則能中止垃圾回收過程.
- 346: Promptly Return Unused Committed Memory from G1 :改進 G1 垃圾回收器,以便在空閒時自動將 Java 堆記憶體返回給作業系統。
1.2 JDK 各版本支援週期
為了更快地迭代,Java的更新從傳統的以特性驅動的釋出週期,轉變為以時間驅動的(6 個月為週期)釋出模式
每半年釋出一個大版本,每個季度釋出一箇中間特性版本,並且承諾不會食言。通過這樣的方式,開發團隊可以把
些關鍵特性儘早合併到 JDK 之中,以快速得到開發者反饋,按照官方的說法,新的釋出週期會嚴格遵循時間點,將於每年的3月份和9月份釋出。所以 Java 11 的版本號是18.9(LTS,long term support)。Oracle 直到2023年9月都會為 Java 11 提供技術支援,而補丁和安全警告等擴充套件支援將持續到2026年。新的長期支援版本每三年釋出一次,根據後續的釋出計劃,下一個長期支援版 Java 17 將於2021年釋出
1.3 目前企業JDK版本使用現狀
在 JDK 版本的世界裡,從來都是 Oracle 發他的新版本,我們繼續用我們的老版本。三年之前用 JDK 7,後來終於升級到了 JDK 8。自從升級了沒多久,JDK 就開始了半年發一個新版本的節奏,陸續釋出了 9 、10、11、12,直到(2019年9月17日)釋出了 JDK13。
開發人員在生產中為其應用程式使用了哪些產品?我們可以看到Oracle JDK和OpenJDK在其他所有人的主導地位。2018年12月,由 Snyk 和 The Java Magazine 聯合推出釋出的 2018 JVM 生態調查報告 顯示有 70% 的使用者使用 Oracle JDK,21% 的使用者使用 OpenJDK。
Java 9中的JDK進行了重大的結構更改,許多人預測這將影響遷移和採用。從結果中我們可以看到(請注意,調查是在Java 10和Java 11發行之間進行的),Java 8仍然是Java的最主要版本-十分之八的受訪者表示,他們的主要應用程式在生產中使用了Java 8。同樣重要的是,使用更新版本的非Java 8受訪者不到一半。2018 JVM 生態調查報告](https://snyk.io/blog/jvm-ecosystem-report-2018),[其中 Java 8 的使用者佔到了 79%。
1.4 JDK 13詳細概述
2019年9月17日,國際知名的OpenJDK開源社群釋出了Java程式語言環境的最新版本OpenJDK 13,此次更新是繼半年前 Java 12 這大版本釋出之後的一次常規版本更新,在這一版中,主要帶來了 ZGC 增強、更新 Socket 實現、Switch
表示式,文字塊更新等方面的改動、增強。
1.5 JDK 13 新特性更新列表介紹
網站:http://openjdk.java.net/projects/jdk/13/
1.6 啟動IDEA建立模組整合JDK 13
- 去官網下載JDK 13
- 下載地址:https://www.oracle.com/java/technologies/javase-jdk13-downloads.html
- 啟動IDEA建立一個模組整合JDK 13
JDK 13新特性詳解
2.1 JEP 354 switch表示式(預覽)
引入
擴充套件switch分支選擇語句的寫法。Switch表示式在經過JDK 12的預覽之後,在JDK 13中可以繼續使用。
設計初衷
Java的switch語句是一個變化較大的語法(可能是因為Java的switch語句一直不夠強大、熟悉swift或者js語言的同學可與swift的switch語句對比一下,就會發現Java的switch相對較弱),因為Java的很多版本都在不斷地改進switch語句:JDK 12擴充套件了switch語句,使其可以用作語句或者表示式,並且傳統的和擴充套件的簡化版switch都可以使用。
JDK 12對於switch的增強主要在於簡化書寫形式,提升功能點。
下面簡單回顧一下switch的進化階段:
- 從Java 5+開始,Java的switch語句可使用枚舉了。
- 從Java 7+開始,Java的switch語句支援使用String型別的變數和表示式了。
- 從Java 11+開始,Java的switch語句會自動對省略break導致的貫穿提示警告。
- 但從JDK12開始,Java的switch語句有了很大程度的增強。
- JDK 13的該JEP是從JEP 325]演變而來的。
以前的switch程式
程式碼如下:
public class Demo01{
public static void main(String[] args){
// 宣告變數score,併為其賦值為'C'
var score = 'C';
// 執行switch分支語句
switch (score) {
case 'A':
System.out.println("優秀");
break;
case 'B':
System.out.println("良好");
break;
case 'C':
System.out.println("中");
break;
case 'D':
System.out.println("及格");
break;
case 'E':
System.out.println("不及格");
break;
default:
System.out.println("資料非法!");
}
}
}
這是經典的Java 11以前的switch寫法 ,這裡不能忘記寫break,否則switch就會貫穿、導致程式出現錯誤(JDK 11會提示警告)。
JDK 13不需要break了
在JDK 12之前如果switch忘記寫break將導致貫穿,在JDK 12對switch的這一貫穿性做了改進。你只要將case後面的冒號(:)改成箭頭,那麼你即使不寫break也不會貫穿了,因此上面程式可改寫如下形式:
public class Demo02{
public static void main(String[] args){
// 宣告變數score,併為其賦值為'C'
var score = 'C';
// 執行switch分支語句
switch (score){
case 'A' -> System.out.println("優秀");
case 'B' -> System.out.println("良好");
case 'C' -> System.out.println("中");
case 'D' -> System.out.println("及格");
case 'E' -> System.out.println("不及格");
default -> System.out.println("成績資料非法!");
}
}
}
上面程式碼簡潔很多了。
JDK 13的switch表示式
JDK 12之後的switch甚至可作為表示式了——不再是單獨的語句。例如如下程式。
public class Demo03 {
public static void main(String[] args) {
// 宣告變數score,併為其賦值為'C'
var score = 'C';
// 執行switch分支語句
String s = switch (score)
{
case 'A' -> "優秀";
case 'B' -> "良好";
case 'C' -> "中";
case 'D' -> "及格";
case 'F' -> "不及格";
default -> "成績輸入錯誤";
};
System.out.println(s);
}
}
上面程式直接將switch表示式的值賦值給s變數,這樣switch不再是一個語句,而是一個表示式.
JDK 13中switch的多值匹配
當你把switch中的case後的冒號改為箭頭之後,此時switch就不會貫穿了,但在某些情況下,程式本來就希望貫穿比如我就希望兩個case共用一個執行體!JDK 12之後的switch中的case也支援多值匹配,這樣程式就變得更加簡潔了。例如如下程式。
public class Demo04
{
public static void main(String[] args)
{
// 宣告變數score,併為其賦值為'C'
var score = 'B';
// 執行switch分支語句
String s = switch (score)
{
case 'A', 'B' -> "上等";
case 'C' -> "中等";
case 'D', 'E' -> "下等";
default -> "成績資料輸入非法!";
};
System.out.println(s);
}
}
JDK 13的Yielding a value
當使用箭頭標籤時,箭頭標籤右邊可以是表示式、throw
語句或是程式碼塊。如果是程式碼塊,需要使用yield
語句來返回值。下面程式碼中的print方法中的default
語句的右邊是一個程式碼塊。在程式碼塊中使用yield
來返回值。,JDK 13引入了一個新的yield
語句來產生一個值,該值成為封閉的switch表示式的值。
public void print(int days) {
// 宣告變數score,併為其賦值為'C'
var score = 'B';
String result = switch (score) {
case 'A', 'B' -> "上等";
case 'C' -> "中等";
case 'D', 'E' -> "下等";
default -> {
if (score > 100) {
yield "資料不能超過100";
} else {
yield score + "此分數低於0分";
}
}
};
System.out.println(result);
}
在switch
表示式中不能使用break
。switch
表示式的每個標籤都必須產生一個值,或者丟擲異常。switch
表示式必須窮盡所有可能的值。這意味著通常需要一個default
語句。一個例外是列舉型別。如果窮盡了列舉型別的所有可能值,則不需要使用default
。在這種情況下,編譯器會自動生成一個default
語句。這是因為列舉型別中的列舉值可能發生變化。比如,列舉型別Color
中原來只有3個值:RED
、GREEN
和BLUE
。使用該列舉型別的switch
表示式窮盡了3種情況並完成編譯。之後Color
中增加了一個新的值YELLOW
,當用這個新的值呼叫之前的程式碼時,由於不能匹配已有的值,編譯器產生的default
會被呼叫,告知列舉型別發生改變
小結
從以上案例可以看出JDK 12到JDK 13對switch的功能做了很大的改進,程式碼也十分的簡化,目前來看switch依然是不支援區間匹配的,未來是否可以支援,我們拭目以待。
2.2 JEP 355 文字塊升級(預覽)
引入
在Java中,在字串文字中嵌入HTML,XML,SQL或JSON片段"..."
通常需要先進行轉義和串聯的大量編輯,然後才能編譯包含該片段的程式碼。該程式碼段通常難以閱讀且難以維護,因此,如果具有一種語言學機制,可以比多行文字更直觀地表示字串,而且可以跨越多行,而且不會出現轉義的視覺混亂,那麼這將提高廣泛Java類程式的可讀性和可寫性。從JDK 13到JDK 13開始文字塊新特性的提出,提高了Java程式書寫大段字串文字的可讀性和方便性。
HTML示例
使用“一維”字串文字*
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
使用“二維”文字塊
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
System.out.println("""
Hello,
itheima
text blocks!
""");
文字塊是Java語言的新語法,可以用來表示任何字串,具有更高的表達能力和更少的複雜度。文字塊的開頭定界符是由三個雙引號 """ 開始,從新的一行開始字串的內容。這裡的新起的這行不屬於字串,只表示內容開始,是語法的一部分。以 """ 結束。 """ 可以緊跟字串內容,也可以另起一行。另起一行時,字串內容最後會留有一新行。
"""
line 1
line 2
line 3
"""
等效於字串文字:
"line 1\nline 2\nline 3\n"
或字串文字的串聯:
"line 1\n" +
"line 2\n" +
"line 3\n"
如果在字串的末尾不需要行終止符,則可以將結束定界符放在內容的最後一行。例如,文字塊:
"""
line 1
line 2
line 3"""
等效於字串文字:
"line 1\nline 2\nline 3"
文字塊可以表示空字串,儘管不建議這樣做,因為它需要兩行原始碼:
String empty = """
""";
以下是一些格式錯誤的文字塊的示例:
String a = """"""; // no line terminator after opening delimiter
String b = """ """; // no line terminator after opening delimiter
String c = """
"; // no closing delimiter (text block continues to EOF)
String d = """
abc \ def
"""; // unescaped backslash (see below for escape processing)
HTML
使用原始字串語法:
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
使用文字塊文字塊語法:
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
SQL
使用原始的字串語法:
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
"WHERE `CITY` = 'INDIANAPOLIS'\n" +
"ORDER BY `EMP_ID`, `LAST_NAME`;\n";
使用文字塊語法:
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";
多語言示例
使用原始的字串語法:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("function hello() {\n" +
" print('\"Hello, world\"');\n" +
"}\n" +
"\n" +
"hello();\n");
使用文字塊語法:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("""
function hello() {
print('"Hello, world"');
}
hello();
""");
縮排
java編譯器會自動刪除不需要的縮排:
- 每行結尾的空格都會刪除
- 每行開始的共有的空格會自動刪除
- 只保留相對縮排。
System.out.println("""
Hello,
itheima
text blocks!
""");
// 結果
// > Hello,
// > itheima
// > text blocks!
// >
System.out.println("""
Hello,
itheima
text blocks!
""");
// 結果
// > Hello,
// > itheima
// > text blocks!
// >
- 新行 """ 結束時,將 """ 向左調整,則可以給所有行前加相應數量的空格。將 """ 向右調整,沒有作用。
System.out.println("""
Hello,
multiline
text blocks!
""");
// 結果
// > Hello,
// > multiline
// > text blocks!
2.3 JEP 350 動態類資料共享歸檔
作用:允許在Java應用程式執行結束時動態歸檔類。歸檔的類將包括預設基層CDS歸檔中不存在的所有已載入應用程式類和庫類。
CDS,是java 12的特性了,可以讓不同 Java 程序之間共享一份類元資料,減少記憶體佔用,它還能加快應用的啟動速度。而JDK13的這個特性支援在Java application執行之後進行動態archive。存檔類將包括預設的基礎層CDS存檔中不存在的所有已載入的應用程式和庫類。也就是說,在Java 13中再使用AppCDS的時候,就不再需要這麼複雜了。該提案處於目標階段,旨在提高AppCDS的可用性,並消除使用者進行試執行以建立每個應用程式的類列表的需要。
目標
JDK13這次對CDS增強的主要目的
- 改善AppCDS的可用性,減少使用者每次都要建立一個類列表的需要
- 通過開啟,
-Xshare:dump
選項來開啟靜態歸檔,使用類列表仍然行得通。會包含內建的類載入資訊和使用者定義的類載入資訊
意義
在JDK13中做的增強,可以只開啟命令列選項完成上面過程,在程式執行的時候,動態評估那些類需要歸檔,同時支援內建的類載入器和使用者定義的類載入器。
在第一次程式執行完成之後,會自動的將類進行歸檔,後續在啟動專案的時候也無需指定要使用哪些歸檔,整個過程看起來更加的透明。
2.4 JEP 351 ZGC 增強: ZGC 釋放未使用記憶體
目標
作用:將未使用的堆記憶體還給系統(即未提交的記憶體空間)
詳解
ZGC 是 Java 11 中引入的最為矚目的垃圾回收特性,是一種可伸縮、低延遲的垃圾收集器,不過在 Java 11 中是實驗性的引入,主要用來改善 GC 停頓時間,並支援幾百 MB 至幾個 TB 級別大小的堆,並且應用吞吐能力下降不會超過 15%,目前只支援 Linux/x64 位平臺的這樣一種新型垃圾收集器。
通過在實際中的使用,發現 ZGC 收集器中並沒有像 Hotspot 中的 G1 和 Shenandoah 垃圾收集器一樣,能夠主動將未使用的記憶體釋放給作業系統的功能。對於大多數應用程式來說,CPU 和記憶體都屬於有限的緊缺資源,特別是現在使用的雲上或者虛擬化環境中。如果應用程式中的記憶體長期處於空閒狀態,並且還不能釋放給作業系統,這樣會導致其他需要記憶體的應用無法分配到需要的記憶體,而這邊應用分配的記憶體還處於空閒狀態,處於"忙的太忙,閒的太閒"的非公平狀態,並且也容易導致基於虛擬化的環境中,因為這些實際並未使用的資源而多付費的情況。由此可見,將未使用記憶體釋放給系統主記憶體是一項非常有用且亟需的功能。
Java 13 中對 ZGC 的改進,主要體現在下面幾點:
- 釋放未使用記憶體給作業系統
- 支援最大堆大小為 16TB
Java 13 中,ZGC 記憶體釋放功能,預設情況下是開啟的,不過可以使用引數:-XX:-ZUncommit
顯式關閉。
2.5 JEP 353 重新實現舊版Socket API
引入
現在已有的 java.net.Socket 和 java.net.ServerSocket 以及它們的實現類,都可以回溯到 JDK 1.0 時代了。原始socket的維護和除錯都很痛苦。實現類還使用了執行緒棧作為 I/O 的緩衝,導致在某些情況下還需要增加執行緒棧的大小。該實現還存在幾個併發問題,需要徹底解決。在未來的網路世界,要快速響應,不能阻塞本地方法執行緒,當前的實現不適合使用了。
詳解
新的實現類
在 Java 13 之前,通過使用 PlainSocketImpl
作為 SocketImpl
的具體實現。
Java 13 中的新底層實現,引入 NioSocketImpl
的實現用以替換 SocketImpl
的 PlainSocketImpl
實現,此實現與 NIO(新 I/O)實現共享相同的內部基礎結構,並且與現有的緩衝區快取記憶體機制整合在一起,因此不需要使用執行緒堆疊。除了這些更改之外,還有其他一些更便利的更改,如使用 java.lang.ref.Cleaner
機制來關閉套接字(如果 SocketImpl
實現在尚未關閉的套接字上被進行了垃圾收集),以及在輪詢時套接字處於非阻塞模式時處理超時操作等方面。
全新實現的 NioSocketImpl 來替換JDK1.0的PlainSocketImpl。
- 它便於維護和除錯,與 NewI/O (NIO) 使用相同的 JDK 內部結構,因此不需要使用系統原生代碼。
- 它與現有的緩衝區快取機制整合在一起,這樣就不需要為 I/O 使用執行緒棧。
- 它使用 java.util.concurrent 鎖,而不是 synchronized 同步方法,增強了併發能力。
- 新的實現是Java 13中的預設實現,但是舊的實現還沒有刪除,可以通過設定系統屬性
jdk.net.usePlainSocketImpl來切換到舊版本。
程式碼說明
執行一個例項化Socket和ServerSocket的類將顯示這個除錯輸出。這是預設的(新的)。
Module java.base
Package java.net
Class SocketImpl
public abstract class SocketImpl implements SocketOptions {
private static final boolean USE_PLAINSOCKETIMPL = usePlainSocketImpl();
private static boolean usePlainSocketImpl() {
PrivilegedAction<String> pa = () ->
NetProperties.get("jdk.net.usePlainSocketImpl");
String s = AccessController.doPrivileged(pa);
return (s != null) && !s.equalsIgnoreCase("false");
}
/**
Creates an instance of platform's SocketImpl
*/
@SuppressWarnings("unchecked")static <S extends SocketImpl & PlatformSocketImpl> S
createPlatformSocketImpl(boolean server) {
if (USE_PLAINSOCKETIMPL) {
return (S) new PlainSocketImpl(server);
} else {
return (S) new NioSocketImpl(server);
}
}
}
SocketImpl的USE_PLAINSOCKETIMPL取決於usePlainSocketImpl方法,而它會從NetProperties讀取
dk.net.usePlainSocketImpl配置,如果不為null且不為false,則usePlainSocketImpl方法返回true;
createPlatformSocketImpl會根據USE_PLAINSOCKETIMPL來建立PlainSocketImpl或者NioSocketImpl。
通過這些更改,Java Socket API 將更易於維護,更好地維護將使套接字程式碼的可靠性得到改善。同時 NIO 實現也可以在基礎層面完成,從而保持 Socket 和 ServerSocket 類層面上的不變。
2.6 其他特性
上面列出的是大方面的特性,除此之外還有一些api的更新及廢棄,主要見 JDK 13 Release Notes,這裡舉幾個例
子。
https://jdk.java.net/13/release-notes
增加項
新增FileSystems.newFileSystem(Path, Map<String, ?>) Method
新的java.nio.ByteBuffer Bulk get/put Methods Transfer Bytes Without Regard to Buffer Position
支援Unicode 12.1
新增-XX:SoftMaxHeapSize Flag,目前僅僅對ZGC起作用
ZGC的最大heap大小增大到16TB
移除項
移除awt.toolkit System Property
移除Runtime Trace Methods
移除-XX:+AggressiveOpts
移除Two Comodo Root CA Certificates、Two DocuSign Root CA Certificates
移除內部的com.sun.net.ssl包
廢棄項
廢棄-Xverify:none及-noverify
廢棄rmic Tool並準備移除
廢棄javax.security.cert並準備移除
已知問題
不再支援Windows 2019 Core Server
使用ZIP File System (zipfs) Provider來更新包含Uncompressed Entries的ZIP或JAR可能造成檔案損壞
展望
Java 在更新發布週期為每半年釋出一次之後,在合併關鍵特性、快速得到開發者反饋等方面,做得越來越好。從 Java 11 到 Java 13,目前確實是嚴格保持半年更新的節奏。Java 13 版本的釋出帶來了些新特性和功能增強、效能提升和改進嘗試。
以上包含的5個特性,能夠改變開發者的編碼風格的主要有Text Blocks和Switch Expressions兩個新特性,但是這兩個特性還處於預覽階段。
而且,JDK13並不是LTS(長期支援)版本,如果你正在使用Java 8(LTS)或者Java 11(LTS),暫時可以不必升級到Java 13。