點擊上方 "程序員小樂"關注, 星標或置頂一起成長
每天凌晨00點00分, 第一時間與你相約
每日英文
You can't just sit there and wait for life to come to you. You have to go get it.
你不能無所事事的坐等人生帶給你一切,你必須得自己努力爭取。
每日掏心話
生活總會給你另一個機會,這個機會叫明天。生活沒有過去,也沒有曾經,不管什麼事只要過去了,就會慢慢忘掉。
來自:覃佑樺 | 責編:樂樂
鏈接:techgeeknext.com/java/java14-features
程序員小樂(ID:study_tech)第 844 次推文 圖片來自百度
往日回顧:手把手教你如何搭建一款自己的私有百度網盤?
正文
Java14發佈了!
2020年3月17日,世界上使用最多的編程語言和應用開發平臺JavaSE 14及JDK14發佈了。Java14發佈了大量JEP(Java增強建議)。新版包含的JEP數量甚至比Java12和13的總和還要多。
Java14主要加入了16個新特性(JEP),包括最新的Java API、JDK Fight Recorder監控等等。完整的新特性列表如下:
1. instanceof模式匹配(預覽特性)2. 非易失性映射字節緩衝(孵化器)3. 實用的NullPointerException4. 新switch表達式(標準特性)5. 打包工具(孵化器)6. G1中的NUMA內存分配優化7. JFR事件流8. Records(預覽特性)9. 棄用Solaris和SPARC端口10. 移除CMS垃圾回收器11. 針對macOS的ZGC(實驗特性)12. 針對Windows的ZGC(實驗特性)13. 棄用ParallelScavenge+SerialOld GC組合14. 移除Pack200工具和API15. 文本塊(第二次預覽版)16. 外存訪問API(孵化器)
Oracle為所有開發者和企業用戶開放了Java14下載。
1. instanceof模式匹配
instanceof操作符用來檢查對象引用是否為指定的Type實例,檢查的結果使用boolean返回。Java14對instanceof操作符進行了改進,加入了模式匹配。改進後的instanceof讓實現邏輯變得清晰,不用在條件判斷後再為對象強制類型轉換。
Java14以前if (obj instanceof String) {
String str = (String) obj; // 需要再次聲明和對象轉換
.. str.contains(..)..
}else{
str = ....
}
Java14if (!(obj instanceof String str)) {
.. str.contains(..)..// 不必再聲明str對象進行強制類型轉換
} else {
.. str....
}
更多示例:if (obj instanceof String str && str.length() > 5) {.. str.contains(..)..}
if (obj instanceof String str || str.length() > 5) {.. str.contains(..)..}
注意:只有object不為null時instanceof才會匹配並把結果分配給str。使用instanceof模式匹配可以減少Java程序中進行強制轉換。
2. 非易失性映射字節緩衝(孵化器)
簡要地說,JDK1.4開始Java NIO File API就出現了。
FileChannel MappedByteBuffer 該API將部分文件數據加載到虛擬內存中,然後引入了Path特性。Path是一個接口。使用Java NIO開發時,可以用Path替代java.io.File表示文件或目錄。
現在,Java 14對MappedByteBuffer進行了改進,將部分文件數據加載到非易失性存儲器(NVM)中。NVM非易失性存儲是指類似ROM(只讀存儲器)、閃存、硬盤等存儲器,即使關閉電源數據也不會丟失。易失性存儲器比如RAM,如果關閉電源則無法保存數據。API唯一的變化是加入了一個新枚舉供FileChannel客戶端使用。表示請求映射位於NVM支持的文件系統而非傳統文件系統。
風險與假設
該特性允許通過ByteBuffer將NVM作為堆外資源進行管理。與此相關的增強功能JDK-8153111正在研究將NVM用於堆數據。可能還會考慮使用NVM存儲JVM元數據。不同的NVM管理模式一起使用時也許不兼容,也可能僅僅是不合適。API建議只支持最大2GB映射空間。必要時可以改動實現策略,使其符合,JDK-8180628以突破此限制。
3. 實用的NullPointerException
Java14對JVM生成的NullPointerException異常信息進行了改進。程序提前終止時,新特性將為開發者和技術支持人員提供有用的信息。由於NPE幾乎可以出現在程序中的任何位置,嘗試捕獲它們並從中恢復通常不太可行。開發人員只能靠JVM確認NPE實際的發生時間。例如,假設下面代碼拋出一個NPE:a.i = 99;
JVM會輸出導致NPE的方法、文件名和行號:Exception in thread "main" java.lang.NullPointerException
at Prog.main(Prog.java:5)
現在假設下面代碼拋出一個NPE:a.b.c.i = 99;
僅通過文件名和行號並不能精確指出究竟哪個變量為null。是變量a、變量b還是變量c?
JDK14 JEP改進了異常信息,按照下面的方式拋出該異常,能夠確切知道哪個變量為null。Exception in thread "main" java.lang.NullPointerException:
Cannot read field 'c' because 'a.b' is null.
at Prog.main(Prog.java:5)
與此同時也帶來一些風險。null詳細信息可能包含源代碼中的變量名。暴露這些信息可能會帶來安全風險。
4. 新switch表達式(標準特性)
Java14擴展了switch語句的功能,可以把switch作為表達式使用。支持箭頭(->)操作符生成或返回值。該特性在JDK12和JDK13中是預覽功能。
例1Java14以前switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
Java14
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
例2Java14以前
int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
case THURSDAY:
case SATURDAY:
numLetters = 8;
break;
case WEDNESDAY:
numLetters = 9;
break;
default:
throw new IllegalStateException("Wat: " + day);
}
Java14int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
更多示例 // 箭頭標籤
static void grade(int g) {
System.out.println(
switch (g) {
case 1 -> "A";
case 2 -> "B";
default -> "C";
}
);
}
------------------------------------------
// 生成值-引入新的yield用法
int j = switch (day) {
case MONDAY -> 0;
case TUESDAY -> 1;
default -> {
int d = day.toString().length();
int result = f(d);
yield result;
}
};
5. 打包工具(孵化器)
該特性是一種能夠簡化安裝過流程的打包功能,能解決應用所需的各種依賴項。有時僅提供一個JAR文件是不夠的,還需要提供原生安裝包。打包工具還可以作為其它技術的補充。
jpackage工具把Java應用打包成平臺特定格式的包,其中包含應用所有的依賴項。即一組普通JAR文件或模塊的集合。支持的包格式:
1. Linux:deb和rpm2. macOS:pkg和dmg3. Windows:MSI和EXE
6. G1中的NUMA內存分配優化
非一致性內存訪問(NUMA)是一種將微處理器集群配置為多處理系統的方式,因此可以在本地共享內存、提高性能並擴展系統能力。Java14實現了NUMA內存分配優化,提升G1在大型計算機上表現。G1中的堆是一組固定大小區域。雖然指定-XX:+UseLargePages選項可以使用大頁面,多個區域可以組成一個物理頁面,但是一個區域通常是一組物理頁面。如果指定+XX:+UseNUMA選項,初始化JVM時上述將把區域平均分佈在所有可用NUMA節點上。
7. JFR事件流
Java14提供了一個新的API,JDK Flight Recorder(JFR)可以通過它持續監視進程內與進程外部應用程序。
使用非Stream方式記錄相同的事件集,開銷可能甚至小於1%。事件流將與非Stream方式同時執行。
jdk.jfr.consumer包位於 jdk.jfr模塊中,擴展了異步訂閱事件的功能。
8.Record(預覽特性)
這是JDK14中一個預覽功能。使用record精簡類聲明代碼。
定義一個數據類需要編寫很多低效重複的模板代碼:構造函數、accessor、equals()、hashCode()、toString()等。Java計劃使用record精簡這些重複代碼。
示例:Java14以前: final class Point {
public final int x;
public final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// equals、hashCode、toString方法
// 其它什麼也沒幹
Java14使用record record Point(int x, int y) { }
使用record的侷限:
· record不能繼承其它類,除了描述狀態的私有final字段外不能聲明其它字段實例。
· record默認為final且不能聲明為abstract。這意味著record API完全由狀態定定義,不能被其它類或者其它record修改。
· record組件隱式定義為final。
9. 棄用Solaris和SPARC端口
· Java14棄用了Solaris/SPARC、Solaris/x64和Linux/SPARC端口,未來可能將它們移除。
· 取消對這些端口的支持,能讓OpenJDK社區的貢獻者加速開發新功能,推動平臺向前發展。
構建配置變化下面嘗試配置Solaris/SPARC $ bash ./configure
...
checking compilation type... native
configure: error: The Solaris and SPARC ports are deprecated and may be removed in a future release.\
Use --enable-deprecated-ports=yes to suppress this error.
configure exiting with result code 1
$
設置--enable-deprecated-port=yes構建選項可以解決錯誤繼續配置。 $ bash ./configure --enable-deprecated-ports=yes
...
checking compilation type... native
configure: WARNING: The Solaris and SPARC ports are deprecated and may be removed in a future release.
...
Build performance summary:
* Cores to use: 32
* Memory limit: 96601 MB
構建Solaris和SPARC版本會報告錯誤或警告,包括Solaris/SPARC、Solaris/x64、Linux/SPARC。
10. 移除CMS垃圾回收器
Java14刪除了CMS垃圾收集器。
不僅停用CMS編譯,從源代碼中刪除了gc/cms目錄中的內容,而且刪除了僅限CMS的選項。
使用-XX:+UseConcMarkSweepGC選項啟用CMS時會提示以下警告: Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; \
support was removed in
虛擬機會繼續使用默認垃圾收集器。
11. JEP 364:針對macOS的ZGC(實驗特性)
JEP 364實際上和JEP3 65一樣。JEP 364針對MacOS提供了ZGC垃圾收集器。它將ZGC垃圾收集器移植到了macOS。正如JEP351中的描述,該JEP的功能還包括使用收集器釋放未使用的設備內存。自Java13開始就支持此功能。ZGC的macOS實現包含兩個部分:
1. 在macOS上支持多重映射(multi-mapping)內存。
2. ZGC支持不連續預留內存。
12. JEP 365:針對Windows的ZGC(實驗特性)
JEP 365實際上和JEP 364一樣。JEP 365針對Windows提供了ZGC垃圾收集器支持。
大多數ZGC代碼都與平臺無關,不需要為Windows修改。由於早期版本沒有預留內存必須的API,因此不支持Windows 10和Windows Server 1803之前的版本。
ZGC的Windows實現進行了以下工作:
1. 支持多重映射內存
由於ZGC使用著色指針(colored pointer),因此需要多重映射支持,以便可以從進程地址空間中的多個位置訪問相同的物理內存。Windows內存使用分頁文件為物理內存提供了一個標識(句柄),與映射的虛擬內存地址無關。ZGC使用該標識可以將相同的物理內存映射到多個地址。
2. 支持將內存映射到預留地址空間,基於分頁文件技術。
Windows內存管理API沒有POSIX mmap/munmap靈活,當涉及到將文件備份內存映射到之前預留的空間時尤其如此。因此,ZGC使用了Windows地址佔位符概念。在Windows 10 V1803和Windows Server中引入了佔位符概念。ZGC不支持Windows其它早期版本。
3. 支持堆內存任意區域映射與取消映射操作。
ZGC堆的佈局要求支持任意粒度的內存映射和取消映射,以及堆頁面動態調整大小與重新調整。此要求與Windows地址空間佔位符結合使用時,需要特別注意,因為佔位符必須由程序顯式拆分/合併,而不是由操作系統自動拆分/合併(與Linux一樣)。
4. 支持堆內存任意區域提交和撤銷提交操作。
ZGC能在Java程序運行時動態提交和撤銷物理內存。為了支持這些操作,物理內存被分為多個分頁文件片段。每個片段都對應一個ZGC堆單元,可以獨立提交和撤銷。
13. JEP 366:棄用ParallelScavenge+SerialOld GC組合
JEP366包含垃圾收集器,它的目標是棄用Parallel Scavenge和Serial Old垃圾收集算法的組合。除了棄用-XX:+UseParallelGC-XX :- UseParallelOldGC組合之外,-XX:UseParallelOld GC選項也被棄用,因為它的作用是取消老年代並行GC,支持老年代串行GC。因此,任何與UseUseParallelOldGC選項有關的用法都會輸出警告。
14. JEP 367:移除Pack200工具和API
Pack 200是JavaSE 5.0中JSR 200實現的JAR文件壓縮方案。
Java14從java.util.jar包中移除了pack200和unpack200工具以及pack200 API。這些工具和API在JavaSE 11中已廢棄,會在隨後的版本中移除。該JEP最終會從JDK主版本中移除3種類型。即之前標記 @Deprecated(forRemoval = true) 註解的基礎模塊:
· java.util.jar.Pack200· java.util.jar.Pack200.Packer· java.util.jar.Pack200.Unpacker
15. JEP 368:文本塊(第二次預覽版)
在Java中,想要把HTML、XML、SQL或JSON代碼片段嵌入到代碼中通常難以閱讀和保留。並且為了克服此問題,Java14 引入了文本塊(Text Block)。
文本塊包含零個或多個字符,這些字符由開始分隔符和結束分隔符包圍。
沒有使用文本塊HTML示例 String html = "\n" +
" \n" +
"
Hello, world
\n" +" \n" +
"\n";
文本塊的開始分隔符以三個雙引號(""")開始,可以接零個或多個空格,最後是一個換行符。開始分隔符換行後面接著是文本塊的內容。
結束分隔符同樣是三個雙引號。文本塊內容在三個雙引號之前結束。
與String不同,文本塊中可以直接使用雙引號。當然也可以使用" 但不是必需的。選擇寬分隔符(""")的好處是可以直接使用"不需要轉義,而且能從視覺上把文本塊與String進行區分。
文本塊是多行String文本。使用文本塊能避免大多數轉義的情況,支持自動格式化字符串,並且在必要時開發者能自行格式化字符串。
使用文本塊的HTML示例 String html = """
Hello, world
""";
2019年初,JEP 355提議把文本塊功能作為JEP 326(原始字符串字)的後續改進,隨後該提議被撤回。
2019年中,JDK13把文本塊作為預覽功能加入,接著Java14加入了兩個新的轉義符。
其一,用\表示換行。其二,是用/s表示一個空格。
換行符示例:// 不使用文本塊
String literal = "two escape sequences first is for newlines " +
"and, second is to signify white space " +
"or single space.";
// 使用 \ 看起來像這樣:
String text = """
two escape sequences first is for newlines \
and, second is to signify white space \
or single space.\
""";
空白或單空格示例: // 在每行的結尾使用 \s,保證每行的長度為6個字節
String colors = """
aaa\s
bbb\s
ccc\s
""";
16. JEP 370:外存訪問API(孵化器)
許多流行的Java庫和程序都支持訪問外部存儲器,例如Ignite、MapDB、Memcached和Netty的ByteBuf API。這樣可以避免垃圾回收(比如維護大型緩存)、跨進程共享內存、通過將文件內存映射進行序列化和反序列化(例如mmap)帶來的開銷以及引入的不可預測性。然而,Java API沒有提供適合的外存訪問解決方案。
Java14通過JEP 370引入了高效的Java API,使得Java應用程序能夠安全有效地訪問Java堆外內存。外部存儲API提出了三個重要的抽象:MemorySegment、MemoryAddress和MemoryLayout。
歡迎在留言區留下你的觀點,一起討論提高。如果今天的文章讓你有新的啟發,學習能力的提升上有新的認識,歡迎轉發分享給更多人。
猜你還想看
阿里、騰訊、百度、華為、京東最新面試題彙集
5萬字長文!SpringBoot 操作 ElasticSearch 詳解
關於 MyBatis 我總結了 10 種通用的寫法
分佈式事務之 RocketMQ 事務消息詳解
關注訂閱號「程序員小樂」,收看更多精彩內容
嘿,你在看嗎?