北京時(shí)間 3 月 21 日谐鼎,Oracle 官方宣布 Java 10 正式發(fā)布舰蟆。這是 Java 大版本周期變化后的第一個(gè)正式發(fā)布版本(詳見(jiàn)這里)趣惠,非常值得關(guān)注。你可以點(diǎn)擊以下地址即刻下載:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
去年 9 月身害,Oracle 將 Java 大版本周期從原來(lái)的 2-3 年味悄,調(diào)整成每半年發(fā)布一個(gè)大的版本。而版本號(hào)仍延續(xù)原來(lái)的序號(hào)塌鸯,即 Java 8侍瑟、Java 9、Java 10丙猬、Java 11.....
但和之前不一樣的是涨颜,同時(shí)還有一個(gè)版本號(hào)來(lái)表示發(fā)布的時(shí)間和是否為 LTS(長(zhǎng)期支持版本),比如 Java 10 對(duì)應(yīng) 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 版本庭瑰。和過(guò)去的 Java 大版本升級(jí)不同,這兩個(gè)只有半年左右的開(kāi)發(fā)和維護(hù)期抢埋。而未來(lái)的 Java 11弹灭,也就是 18.9 LTS,才是 Java 8 之后第一個(gè) LTS 版本(得到 Oracle 等商業(yè)公司的長(zhǎng)期支持服務(wù))揪垄。
這種發(fā)布模式已經(jīng)得到了廣泛應(yīng)用穷吮,一個(gè)成功的例子就是 Ubuntu Linux 操作系統(tǒng),在偶數(shù)年 4 月的發(fā)行版本為 LTS饥努,會(huì)有很長(zhǎng)時(shí)間的支持酒来。如 2014 年 4 月份發(fā)布的 14.04 LTS,Canonical 公司和社區(qū)支持到 2019 年肪凛。類似的堰汉,Node.js,Linux kernel伟墙,F(xiàn)irefox 也采用類似的發(fā)布方式翘鸭。
Java 未來(lái)的發(fā)布周期,將每半年發(fā)布一個(gè)大版本戳葵,每個(gè)季度發(fā)布一個(gè)中間特性版本就乓。這樣可以把一些關(guān)鍵特性盡早合并入 JDK 之中,快速得到開(kāi)發(fā)者反饋拱烁,可以在一定程度上避免 Java 9 兩次被迫推遲發(fā)布日期的尷尬生蚁。
下圖為 2017 年 JavaOne 大會(huì)時(shí),Oracle 公開(kāi)的未來(lái) Java 版本發(fā)布和支持周期圖戏自。
Java 10 新特性
這次發(fā)布的 Java 10邦投,新帶來(lái)的特性并不多。
根據(jù)官網(wǎng)公開(kāi)資料擅笔,共有 12 個(gè) JEP(JDK Enhancement Proposal 特性加強(qiáng)提議)志衣,帶來(lái)以下加強(qiáng)功能:
JEP286屯援,var 局部變量類型推斷。
JEP296念脯,將原來(lái)用 Mercurial 管理的眾多 JDK 倉(cāng)庫(kù)代碼狞洋,合并到一個(gè)倉(cāng)庫(kù)中,簡(jiǎn)化開(kāi)發(fā)和管理過(guò)程绿店。
JEP304吉懊,統(tǒng)一的垃圾回收接口。
JEP307假勿,G1 垃圾回收器的并行完整垃圾回收惕它,實(shí)現(xiàn)并行性來(lái)改善最壞情況下的延遲。
JEP310废登,應(yīng)用程序類數(shù)據(jù) (AppCDS) 共享,通過(guò)跨進(jìn)程共享通用類元數(shù)據(jù)來(lái)減少內(nèi)存占用空間郁惜,和減少啟動(dòng)時(shí)間堡距。
JEP312,ThreadLocal 握手交互兆蕉。在不進(jìn)入到全局 JVM 安全點(diǎn) (Safepoint) 的情況下羽戒,對(duì)線程執(zhí)行回調(diào)。優(yōu)化可以只停止單個(gè)線程虎韵,而不是停全部線程或一個(gè)都不停易稠。
JEP313,移除 JDK 中附帶的 javah 工具包蓝∈簧纾可以使用 javac -h 代替。
JEP314测萎,使用附加的 Unicode 語(yǔ)言標(biāo)記擴(kuò)展亡电。
JEP317,能將堆內(nèi)存占用分配給用戶指定的備用內(nèi)存設(shè)備硅瞧。
JEP317份乒,使用 Graal 基于 Java 的編譯器,可以預(yù)先把 Java 代碼編譯成本地代碼來(lái)提升效能腕唧。
JEP318或辖,在 OpenJDK 中提供一組默認(rèn)的根證書(shū)頒發(fā)機(jī)構(gòu)證書(shū)。開(kāi)源目前 Oracle 提供的的 Java SE 的根證書(shū)枣接,這樣 OpenJDK 對(duì)開(kāi)發(fā)人員使用起來(lái)更方便颂暇。
JEP322,基于時(shí)間定義的發(fā)布版本但惶,即上述提到的發(fā)布周期蟀架。版本號(hào)為\$FEATURE.\$INTERIM.\$UPDATE.\$PATCH瓣赂,分別是大版本,中間版本片拍,升級(jí)包和補(bǔ)丁版本煌集。
部分特性說(shuō)明
1. var 類型推斷。
這個(gè)語(yǔ)言功能在其他一些語(yǔ)言 (C#捌省、JavaScript) 和基于 JRE 的一些語(yǔ)言 (Scala 和 Kotlin) 中苫纤,早已被加入。
在 Java 語(yǔ)言很早就在考慮纲缓,早在 2016 年正式提交了 JEP286 提議卷拘。后來(lái)舉行了一次公開(kāi)的開(kāi)發(fā)者調(diào)查,獲得最多建議的是采用類似 Scala 的方案祝高,“同時(shí)使用 val 和 var”栗弟,約占一半;第二多的是“只使用 var”工闺,約占四分之一乍赫。后來(lái) Oracle 公司經(jīng)過(guò)慎重考慮,采用了只使用 var 關(guān)鍵字的方案陆蟆。
有了這個(gè)功能雷厂,開(kāi)發(fā)者在寫(xiě)這樣的代碼時(shí):
ArrayList myList = new ArrayList()
可以省去前面的類型聲明,而只需要
var list = new ArrayList()
編譯器會(huì)自動(dòng)推斷出 list 變量的類型叠殷。對(duì)于鏈?zhǔn)奖磉_(dá)式來(lái)說(shuō)改鲫,也會(huì)很方便:
var stream = blocks.stream();
...
int maxWeight = stream.filter(b -> b.getColor() == BLUE)
? ? ? ? ? ? ? ? ? ? ?.mapToInt(Block::getWeight)
? ? ? ? ? ? ? ? ? ? ?.max();
開(kāi)發(fā)者無(wú)須聲明并且 import 引入 Stream 類型,只用 stream 作為中間變量林束,用 var 關(guān)鍵字使得開(kāi)發(fā)效率提升像棘。
不過(guò) var 的使用有眾多限制,包括不能用于推斷方法參數(shù)類型壶冒,只能用于局部變量讲弄,如方法塊中,而不能用于類變量的聲明依痊,等等避除。
另外,我個(gè)人認(rèn)為胸嘁,對(duì)于開(kāi)發(fā)者而言瓶摆,變量類型明顯的聲明會(huì)提供更加全面的程序語(yǔ)言信息,對(duì)于理解并維護(hù)代碼有很大的幫助性宏。一旦 var 被廣泛運(yùn)用群井,開(kāi)發(fā)者閱讀三方代碼而沒(méi)有 IDE 的支持下,會(huì)對(duì)程序的流程執(zhí)行理解造成一定的障礙毫胜。所以我建議盡量寫(xiě)清楚變量類型书斜,程序的易讀維護(hù)性有時(shí)更重要一些诬辈。
2. 統(tǒng)一的 GC 接口
在 JDK10 的代碼中,路徑為 openjdk/src/hotspot/share/gc/荐吉,各個(gè) GC 實(shí)現(xiàn)共享依賴 shared 代碼焙糟,GC 包括目前默認(rèn)的 G1,也有經(jīng)典的 Serial样屠、Parallel穿撮、CMS 等 GC 實(shí)現(xiàn)。
3. 應(yīng)用程序類數(shù)據(jù)(AppCDS)共享
CDS 特性在原來(lái)的 bootstrap 類基礎(chǔ)之上痪欲,擴(kuò)展加入了應(yīng)用類的 CDS(Application Class-Data Sharing) 支持悦穿。
其原理為:在啟動(dòng)時(shí)記錄加載類的過(guò)程,寫(xiě)入到文本文件中业踢,再次啟動(dòng)時(shí)直接讀取此啟動(dòng)文本并加載栗柒。設(shè)想如果應(yīng)用環(huán)境沒(méi)有大的變化,啟動(dòng)速度就會(huì)得到提升知举。
我們可以想像為類似于操作系統(tǒng)的休眠過(guò)程瞬沦,合上電腦時(shí)把當(dāng)前應(yīng)用環(huán)境寫(xiě)入磁盤(pán),再次使用時(shí)就可以快速恢復(fù)環(huán)境负蠕。
我在自己 PC 電腦上做以下應(yīng)用啟動(dòng)實(shí)驗(yàn)。
首先部署 wildfly 12 應(yīng)用服務(wù)器倦畅,采用 JDK10 預(yù)覽版作為 Java 環(huán)境遮糖。另外需要用到一個(gè)工具 cl4cds[1],作用是把加載類的日志記錄叠赐,轉(zhuǎn)換為 AppCDS 可以識(shí)別的格式欲账。
A、安裝好 wildfly 并部署一個(gè)應(yīng)用芭概,具有 Angularjs, rest, jpa 完整應(yīng)用技術(shù)棧赛不,預(yù)熱后啟動(dòng)三次,并記錄完成部署時(shí)間
分別為 6716ms, 6702ms, 6613ms罢洲,平均時(shí)間為 6677ms踢故。
B、加入環(huán)境變量并啟動(dòng)惹苗,導(dǎo)出啟動(dòng)類日志
export PREPEND_JAVA_OPTS="-Xlog:class+load=debug:file=/tmp/wildfly.classtrace"
C殿较、使用 cl4cds 工具,生成 AppCDS 可以識(shí)別的 cls 格式
/jdk-10/bin/java -cp src/classes/ io.simonis.cl4cds /tmp/wildfly.classtrace /tmp/wildfly.cls
打開(kāi)文件可以看到內(nèi)容為:
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
....
這個(gè)文件用于標(biāo)記類的加載信息桩蓉。
D淋纲、使用環(huán)境變量啟動(dòng) wildfly,模擬啟動(dòng)過(guò)程并導(dǎo)出 jsa 文件院究,就是記錄了啟動(dòng)時(shí)類的信息洽瞬。
export PREPEND_JAVA_OPTS="-Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=/tmp/wildfly.cls -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/wildfly.jsa"
查看產(chǎn)生的文件信息本涕,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 文件啟動(dòng)應(yīng)用服務(wù)器
export PREPEND_JAVA_OPTS="-Xshare:on -XX:+UseAppCDS -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=/tmp/wildfly.jsa"
啟動(dòng)完畢后記錄時(shí)長(zhǎng)菩颖,三次分別是 5535ms, 5333ms, 5225ms,平均為 5364ms对供,相比之前的 6677ms 可以算出啟動(dòng)時(shí)間提升了 20% 左右位他。
這個(gè)效率提升,對(duì)于云端應(yīng)用部署很有價(jià)值产场。
以上實(shí)驗(yàn)方法參考于技術(shù)博客 [2]鹅髓。
4. JEP314,使用附加的 Unicode 語(yǔ)言標(biāo)記擴(kuò)展京景。
JDK10 對(duì)于 Unicode BCP 47 有了更多的支持窿冯,BCP 47 是 IETF 定義語(yǔ)言集的規(guī)范文檔。使用擴(kuò)展標(biāo)記确徙,可以更方便的獲得所需要的語(yǔ)言地域環(huán)境醒串。
如 JDK10 加入的一個(gè)方法,
java.time.format.DateTimeFormatter::localizedBy
通過(guò)這個(gè)方法鄙皇,可以采用某種數(shù)字樣式芜赌,區(qū)域定義或者時(shí)區(qū)來(lái)獲得時(shí)間信息所需的語(yǔ)言地域本地環(huán)境信息。
附:從鏈接 [3] 可以看到 JDK10 所有的方法級(jí)別改動(dòng)伴逸。
5. 查看當(dāng)前 JDK 管理根證書(shū)缠沈。
自 JDK9 起在 keytool 中加入?yún)?shù) -cacerts,可以查看當(dāng)前 JDK 管理的根證書(shū)错蝴。而 OpenJDK9 中 cacerts 為空洲愤,這樣就會(huì)給開(kāi)發(fā)者帶來(lái)很多不變。
EP318 就是利用 Oracle 開(kāi)源出 Oracle JavaSE 中的 cacerts 信息顷锰,在 OpenJDK 中提供一組默認(rèn)的根證書(shū)頒發(fā)機(jī)構(gòu)證書(shū)柬赐,目前有 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
......
下一版本展望
下一個(gè) Java 大版本會(huì)是 Java 11官紫,也是 Java 8 之后的 LTS 版本肛宋,預(yù)計(jì)會(huì)在今年的 9 月份發(fā)布。目前只有四個(gè) JEP束世,更多加強(qiáng)提議會(huì)逐步加入悼吱。
這個(gè)版本會(huì)充分發(fā)揮模塊化的能力,把當(dāng)前 JDK 中的關(guān)于 JavaEE 和 Corba 的部分移除良狈,變得更加緊湊后添。
雖然 JDK9 最大的亮點(diǎn)是模塊化,但 Java 業(yè)界廣泛接納并且適應(yīng)需要一個(gè)過(guò)程。當(dāng)前已經(jīng)有一些支持模塊化的類庫(kù)遇西,如 log4j2馅精,但大多數(shù)還未支持。
可以預(yù)見(jiàn) JDK11 發(fā)布之后粱檀,模塊化特性就成為長(zhǎng)期支持特性洲敢,會(huì)有越來(lái)越多的類庫(kù)提供對(duì)模塊化的支持。
Java 依然會(huì)是最適合應(yīng)用開(kāi)發(fā)的語(yǔ)言和平臺(tái)茄蚯,龐大的社區(qū)和廣泛的開(kāi)發(fā)者压彭,會(huì)不斷促使 Java 不斷完善優(yōu)化,在各個(gè)編程領(lǐng)域繼續(xù)發(fā)揚(yáng)光大渗常。