Java 14 新特性速覽,看了都說好

點擊上方 "程序員小樂"關注, 星標或置頂一起成長

每天凌晨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

Java 14 新特性速覽,看了都說好

程序員小樂(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 事務消息詳解

關注訂閱號「程序員小樂」,收看更多精彩內容
嘿,你在看嗎?


分享到:


相關文章: