1. 程式人生 > >Java 10正式釋出,帶來了這些新特性

Java 10正式釋出,帶來了這些新特性

點選上方“程式設計師小灰”,選擇“置頂公眾號”

有趣有內涵的文章第一時間送達!

本文轉載自公眾號  InfoQ

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1作者 | 張建鋒編輯 | 郭蕾

北京時間 3 月 21 日,Oracle 官方宣佈 Java 10 正式釋出。這是 Java 大版本週期變化後的第一個正式釋出版本(詳見這裡),非常值得關注。你可以點選以下地址即刻下載:

http://www.oracle.com/technetwork/java/javase/downloads/index.html

去年 9 月,Oracle 將 Java 大版本週期從原來的 2-3 年,調整成每半年釋出一個大的版本。而版本號仍延續原來的序號,即 Java 8、Java 9、Java 10、Java 11.....

但和之前不一樣的是,同時還有一個版本號來表示釋出的時間和是否為 LTS(長期支援版本),比如 Java 10 對應 18.3。如下示例:

/jdk-10/bin$ ./java -version

openjdk version "10" 2018-03-20

OpenJDK Runtime Environment 18.3 (build 10+46)

OpenJDK 64-Bit Server VM 18.3 (build 10+46, mixed mode)

需要注意的是 Java 9 和 Java 10 都不是 LTS 版本。和過去的 Java 大版本升級不同,這兩個只有半年左右的開發和維護期。而未來的 Java 11,也就是 18.9 LTS,才是 Java 8 之後第一個 LTS 版本(得到 Oracle 等商業公司的長期支援服務)。

這種釋出模式已經得到了廣泛應用,一個成功的例子就是 Ubuntu Linux 作業系統,在偶數年 4 月的發行版本為 LTS,會有很長時間的支援。如 2014 年 4 月份釋出的 14.04 LTS,Canonical 公司和社群支援到 2019 年。類似的,Node.js,Linux kernel,Firefox 也採用類似的釋出方式。

Java 未來的釋出週期,將每半年釋出一個大版本,每個季度釋出一箇中間特性版本。這樣可以把一些關鍵特性儘早合併入 JDK 之中,快速得到開發者反饋,可以在一定程度上避免 Java 9 兩次被迫推遲釋出日期的尷尬。

下圖為 2017 年 JavaOne 大會時,Oracle 公開的未來 Java 版本釋出和支援週期圖。

640?wx_fmt=jpeg

Java 10 新特性

這次釋出的 Java 10,新帶來的特性並不多。

根據官網公開資料,共有 12 個 JEP(JDK Enhancement Proposal 特性加強提議),帶來以下加強功能:

  1. JEP286,var 區域性變數型別推斷。

  2. JEP296,將原來用 Mercurial 管理的眾多 JDK 倉庫程式碼,合併到一個倉庫中,簡化開發和管理過程。

  3. JEP304,統一的垃圾回收介面。

  4. JEP307,G1 垃圾回收器的並行完整垃圾回收,實現並行性來改善最壞情況下的延遲。

  5. JEP310,應用程式類資料 (AppCDS) 共享,通過跨程序共享通用類元資料來減少記憶體佔用空間,和減少啟動時間。

  6. JEP312,ThreadLocal 握手互動。在不進入到全域性 JVM 安全點 (Safepoint) 的情況下,對執行緒執行回撥。優化可以只停止單個執行緒,而不是停全部執行緒或一個都不停。

  7. JEP313,移除 JDK 中附帶的 javah 工具。可以使用 javac -h 代替。

  8. JEP314,使用附加的 Unicode 語言標記擴充套件。

  9. JEP317,能將堆記憶體佔用分配給使用者指定的備用記憶體裝置。

  10. JEP317,使用 Graal 基於 Java 的編譯器,可以預先把 Java 程式碼編譯成原生代碼來提升效能。

  11. JEP318,在 OpenJDK 中提供一組預設的根證書頒發機構證書。開源目前 Oracle 提供的的 Java SE 的根證書,這樣 OpenJDK 對開發人員使用起來更方便。

  12. JEP322,基於時間定義的釋出版本,即上述提到的釋出週期。版本號為\$FEATURE.\$INTERIM.\$UPDATE.\$PATCH,分別是大版本,中間版本,升級包和補丁版本。

部分特性說明

1. var 型別推斷。

這個語言功能在其他一些語言 (C#、JavaScript) 和基於 JRE 的一些語言 (Scala 和 Kotlin) 中,早已被加入。

在 Java 語言很早就在考慮,早在 2016 年正式提交了 JEP286 提議。後來舉行了一次公開的開發者調查,獲得最多建議的是採用類似 Scala 的方案,“同時使用 val 和 var”,約佔一半;第二多的是“只使用 var”,約佔四分之一。後來 Oracle 公司經過慎重考慮,採用了只使用 var 關鍵字的方案。

有了這個功能,開發者在寫這樣的程式碼時:

ArrayList<String> myList = new ArrayList<String>()

可以省去前面的型別宣告,而只需要

var list = new ArrayList<String>()

編譯器會自動推斷出 list 變數的型別。對於鏈式表示式來說,也會很方便:

var stream = blocks.stream(); 

... 

int maxWeight = stream.filter(b -> b.getColor() == BLUE)

                      .mapToInt(Block::getWeight)

                      .max();

開發者無須宣告並且 import 引入 Stream 型別,只用 stream 作為中間變數,用 var 關鍵字使得開發效率提升。

不過 var 的使用有眾多限制,包括不能用於推斷方法引數型別,只能用於區域性變數,如方法塊中,而不能用於類變數的宣告,等等。

另外,我個人認為,對於開發者而言,變數型別明顯的宣告會提供更加全面的程式語言資訊,對於理解並維護程式碼有很大的幫助。一旦 var 被廣泛運用,開發者閱讀三方程式碼而沒有 IDE 的支援下,會對程式的流程執行理解造成一定的障礙。所以我建議儘量寫清楚變數型別,程式的易讀維護性有時更重要一些。

2. 統一的 GC 介面

在 JDK10 的程式碼中,路徑為 openjdk/src/hotspot/share/gc/,各個 GC 實現共享依賴 shared 程式碼,GC 包括目前預設的 G1,也有經典的 Serial、Parallel、CMS 等 GC 實現。

640?wx_fmt=jpeg

3. 應用程式類資料(AppCDS)共享

CDS 特性在原來的 bootstrap 類基礎之上,擴充套件加入了應用類的 CDS(Application Class-Data Sharing) 支援。

其原理為:在啟動時記錄載入類的過程,寫入到文字檔案中,再次啟動時直接讀取此啟動文字並載入。設想如果應用環境沒有大的變化,啟動速度就會得到提升。

我們可以想像為類似於作業系統的休眠過程,合上電腦時把當前應用環境寫入磁碟,再次使用時就可以快速恢復環境。

我在自己 PC 電腦上做以下應用啟動實驗。

首先部署 wildfly 12 應用伺服器,採用 JDK10 預覽版作為 Java 環境。另外需要用到一個工具 cl4cds[1],作用是把載入類的日誌記錄,轉換為 AppCDS 可以識別的格式。

A、安裝好 wildfly 並部署一個應用,具有 Angularjs, rest, jpa 完整應用技術棧,預熱後啟動三次,並記錄完成部署時間

分別為 6716ms, 6702ms, 6613ms,平均時間為 6677ms。

B、加入環境變數並啟動,匯出啟動類日誌

export PREPEND_JAVA_OPTS="-Xlog:class+load=debug:file=/tmp/wildfly.classtrace"

C、使用 cl4cds 工具,生成 AppCDS 可以識別的 cls 格式

/jdk-10/bin/java -cp src/classes/ io.simonis.cl4cds /tmp/wildfly.classtrace /tmp/wildfly.cls

開啟檔案可以看到內容為:

java/lang/Object id: 0x0000000100000eb0

java/io/Serializable id: 0x0000000100001090

java/lang/Comparable id: 0x0000000100001268

java/lang/CharSequence id: 0x0000000100001440

......

org/hibernate/type/AssociationType id: 0x0000000100c61208 super: 0x0000000100000eb0 interfaces: 0x0000000100a00d10 source: /home/shihang/work/jboss/wildfly/dist/target/wildfly-12.0.0.Final/modules/system/layers/base/org/hibernate/main/hibernate-core-5.1.10.Final.jar

org/hibernate/type/AbstractType id: 0x0000000100c613e0 super: 0x0000000100000eb0 interfaces: 0x0000000100a00d10 source: /home/shihang/work/jboss/wildfly/dist/target/wildfly-12.0.0.Final/modules/system/layers/base/org/hibernate/main/hibernate-core-5.1.10.Final.jar

org/hibernate/type/AnyType id: 0x0000000100c61820 super: 0x0000000100c613e0 interfaces: 0x0000000100c61030 0x0000000100c61208 source: /home/shihang/work/jboss/wildfly/dist/target/wildfly-12.0.0.Final/modules/system/layers/base/org/hibernate/main/hibernate-core-5.1.10.Final.jar

....

這個檔案用於標記類的載入資訊。

D、使用環境變數啟動 wildfly,模擬啟動過程並匯出 jsa 檔案,就是記錄了啟動時類的資訊。

export PREPEND_JAVA_OPTS="-Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=/tmp/wildfly.cls -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/wildfly.jsa"

檢視產生的檔案資訊,jsa 檔案有較大的體積。

/opt/work/cl4cds$ ls -l /tmp/wildfly.*

-rw-rw-r-- 1 shihang shihang   8413843 Mar 20 11:07 /tmp/wildfly.classtrace

-rw-rw-r-- 1 shihang shihang   4132654 Mar 20 11:11 /tmp/wildfly.cls

-r--r--r-- 1 shihang shihang 177659904 Mar 20 11:13 /tmp/wildfly.jsa

E、使用 jsa 檔案啟動應用伺服器

export PREPEND_JAVA_OPTS="-Xshare:on -XX:+UseAppCDS -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/wildfly.jsa"

啟動完畢後記錄時長,三次分別是 5535ms, 5333ms, 5225ms,平均為 5364ms,相比之前的 6677ms 可以算出啟動時間提升了 20% 左右。

這個效率提升,對於雲端應用部署很有價值。

以上實驗方法參考於技術部落格 [2]。

4. JEP314,使用附加的 Unicode 語言標記擴充套件。

JDK10 對於 Unicode BCP 47 有了更多的支援,BCP 47 是 IETF 定義語言集的規範文件。使用擴充套件標記,可以更方便的獲得所需要的語言地域環境。

如 JDK10 加入的一個方法,

java.time.format.DateTimeFormatter::localizedBy

通過這個方法,可以採用某種數字樣式,區域定義或者時區來獲得時間資訊所需的語言地域本地環境資訊。

附:從連結 [3] 可以看到 JDK10 所有的方法級別改動。

5. 檢視當前 JDK 管理根證書。

自 JDK9 起在 keytool 中加入引數 -cacerts,可以檢視當前 JDK 管理的根證書。而 OpenJDK9 中 cacerts 為空,這樣就會給開發者帶來很多不變。

EP318 就是利用 Oracle 開源出 Oracle JavaSE 中的 cacerts 資訊,在 OpenJDK 中提供一組預設的根證書頒發機構證書,目前有 80 條記錄。

/jdk-10/bin$ ./keytool -list -cacerts

Enter keystore password:  

Keystore type: JKS

Keystore provider: SUN



Your keystore contains 80 entries



verisignclass2g2ca [jdk], Dec 2, 2017, trustedCertEntry, 

Certificate fingerprint (SHA-256): 3A:43:E2:20:FE:7F:3E:A9:65:3D:1E:21:74:2E:AC:2B:75:C2:0F:D8:98:03:05:BC:50:2C:AF:8C:2D:9B:41:A1

......
下一版本展望

下一個 Java 大版本會是 Java 11,也是 Java 8 之後的 LTS 版本,預計會在今年的 9 月份釋出。目前只有四個 JEP,更多加強提議會逐步加入。

這個版本會充分發揮模組化的能力,把當前 JDK 中的關於 JavaEE 和 Corba 的部分移除,變得更加緊湊。

雖然 JDK9 最大的亮點是模組化,但 Java 業界廣泛接納並且適應需要一個過程。當前已經有一些支援模組化的類庫,如 log4j2,但大多數還未支援。

可以預見 JDK11 釋出之後,模組化特性就成為長期支援特性,會有越來越多的類庫提供對模組化的支援。

Java 依然會是最適合應用開發的語言和平臺,龐大的社群和廣泛的開發者,會不斷促使 Java 不斷完善優化,在各個程式設計領域繼續發揚光大。

對文中引用文章原作者表示致謝!引用的圖示,資料和方法都屬於原作者。下一個 Java 大版本會是 Java 11,也是 Java 8 之後的 LTS 版本,預計會在今年的 9 月份釋出。目前只有四個 JEP,更多加強提議會逐步加入。 這個版本會充分發揮模組化的能力,把當前 JDK 中的關於 JavaEE 和 Corba 的部分移除,變得更加緊湊。 雖然 JDK9 最大的亮點是模組化,但 Java 業界廣泛接納並且適應需要一個過程。當前已經有一些支援模組化的類庫,如 log4j2,但大多數還未支援。 可以預見 JDK11 釋出之後,模組化特性就成為長期支援特性,會有越來越多的類庫提供對模組化的支援。 Java 依然會是最適合應用開發的語言和平臺,龐大的社群和廣泛的開發者,會不斷促使 Java 不斷完善優化,在各個程式設計領域繼續發揚光大。 對文中引用文章原作者表示致謝!引用的圖示,資料和方法都屬於原作者。 

[1]: https://simonis.github.io/cl4cds/ 

[2]: https://marschall.github.io/2018/02/18/wildfly-appcds.html 

[3]:https://gunnarmorling.github.io/jdk-api-diff/jdk9-jdk10-api-diff.html#java.time.format.DateTimeFormatter

—————END—————

喜歡本文的朋友們,歡迎長按下圖關注訂閱號程式設計師小灰,收看更多精彩內容

640?wx_fmt=jpeg