Java 每半年就會更新一次新特性,再不掌握就要落伍了:Java13 的新特性
你好,我是看山。
本文收錄在 《從小工到專家的 Java 進階之旅》 系列專欄中。
從 2017 年開始,Java 版本更新策略從原來的每兩年一個新版本,改為每六個月一個新版本,以快速驗證新特性,推動 Java 的發展。從 《JVM Ecosystem Report 2021》 中可以看出,目前開發環境中有近半的環境使用 Java8,有近半的人轉移到了 Java11,隨著 Java17 的發布,相信比例會有所變化。
因此,準備出一個系列,配合示例講解,闡述各個版本的新特性。
概述
本文講解一下 Java13 的特性,這個版本在語法特性上增加不多,值得關注的是兩個預覽功能:Switch 表達式和文本塊,另外可以關乎的是性能優化方面的:動態類數據共享(CDS)存檔、ZGC 動態釋放未使用內存、Socket API 重構。這些方面可以看出,Java 的升級方向有兩個,一是增加功能,增加新的語法特性;二是增強功能,提升已有功能性能。
預覽功能
Java13 引入了兩個新的語法特性:Switch 表達式和文本塊。這些預覽功能是為了讓開發者嘗鮮的同時,可以快速調整,反饋好就留下,不好就移除。目前來看,這些特性還是挺香的。
Switch 表達式
在 Java12 中 Switch 表達式首次以預覽版的身份出現,在 Java13 中又做了增強,在 Java14 正式提供。Java13 添加了yield關鍵字,用來返回值。
yield與return的區別在于,yield只會跳出switch塊,return是跳出當前方法或循環。
比如下面的例子,在 Java12 之前,要判斷日期可以這樣寫:
@Test void testSwitch() { final DayOfWeek day = DayOfWeek.from(LocalDate.now()); String typeOfDay = ""; switch (day) { case MONDAY: case TUESDAY: case WEDNESDAY: case THURSDAY: case FRIDAY: typeOfDay = "Working Day"; break; case SATURDAY: case SUNDAY: typeOfDay = "Rest Day"; break; } Assertions.assertFalse(typeOfDay.isEmpty()); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在 Java12 提供的 Switch 表達式預覽功能,我們可以簡化一下:
@Test void testSwitchExpression() { final DayOfWeek day = DayOfWeek.SATURDAY; final String typeOfDay = switch (day) { case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Working Day"; case SATURDAY, SUNDAY -> "Day Off"; }; Assertions.assertEquals("Day Off", typeOfDay); }
1
2
3
4
5
6
7
8
9
10
這樣可以實現判斷,但是沒有辦法在表達式中實現其他邏輯了。于是 Java13 補齊了這個功能:
@Test void testSwitchExpression13() { final DayOfWeek day = DayOfWeek.SATURDAY; final String typeOfDay = switch (day) { case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> { System.out.println("Working Day: " + day); yield "Working Day"; } case SATURDAY, SUNDAY -> { System.out.println("Day Off: " + day); yield "Day Off"; } }; Assertions.assertEquals("Day Off", typeOfDay); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
這里需要說明一下,既然是預覽功能,會與正式提供功能有些出入。上面的代碼是在 Java14 環境中編寫,與 Java13 發布的功能描述有些差異,這點不必深究,已經廢棄的約束就是不存在。
文本塊
一直以來,Java 中的字符串定義都是以雙引號括起來的形式,不支持多行書寫,所以在需要多行字符串中,需要使用轉義符表示,既不好看、還不好讀,更不好維護。
千呼萬喚始出來,終于有了文本塊功能。
比如,我們想要寫一段 Json 格式的數據,Java13 之前需要寫成:
String json = "{\n" + " \"wechat\": \"hellokanshan\",\n" + " \"wechatName\": \"看山、",\n" + " \"mp\": \"kanshanshuo\",\n" + " \"mpName\": \"看山的小屋、"\n" + "}\n";
1
2
3
4
5
6
但是在 Java13 預覽版中可以寫作:
String json2 = """ { "wechat": "hellokanshan", "wechatName": "看山", "mp": "kanshanshuo", "mpName": "看山的小屋" } """;
1
2
3
4
5
6
7
8
少了很多的+、換行、轉移等字符,看著更加直觀。
這個功能在 Java15 中正式提供。
動態類數據共享(CDS)存檔
CDS 是 Java5 引入的一種類預處理方式,可以將一組類共享到一個歸檔文件中,借助內存映射加載類數據,減少啟動時間,并可實現在多 JVM 之間共享的功能。在 Java10 對其進行擴展,增大了 CDS 使用范圍,即 AppCDS(參見 Java10 新特性)。到了 Java12,將 CDS 歸檔文件作為了默認功能開放出來(參見 Java12 新特性)。
但是這個功能在使用的時候還是有些麻煩。為了生成歸檔文件,開發人員必須先對應用程序進行試運行,創建一個類列表,然后將其轉儲到歸檔文件中。然后,這個歸檔才可以用來在 JVM 之間共享元數據。
Java13 簡化了這個過程:允許 Java 應用在運行結束后動態歸檔,即將已被加載但不屬于 CDS 的類(包括自定義類和引用庫的類)動態添加到 CDS 歸檔文件中。不用再提供歸檔類的列表,通過更加簡潔的方式創建包含應用程序的歸檔。
我們可以使用-XX:ArchiveClassesAtExit參數控制應用程序退出時創建 CDS 歸檔文件:
java -XX:ArchiveClassesAtExit=
1
也可以使用-XX:SharedArchiveFile來使用動態存檔功能:
java -XX:SharedArchiveFile=
1
ZGC 增強:釋放未使用內存
ZGC 是 Java11 中引入的一個可伸縮、低延遲的垃圾收集器,主要目標包括:GC 停頓時間不超過 10ms;可以處理從幾百 MB 的小堆,到幾個 TB 的大堆;應用吞吐能力不會下降超過 15%等(參見 Java11 的新特性)。
但是 ZGC 并沒有像 Hotspot 中的 G1 和 Shenandoah 那樣,可以主動釋放未使用的內存,對于多數應用程序來說,CPU 和內存都是稀缺資源,尤其是現在云上環境和虛擬化技術,如果應用程序占用的內存長期處于空閑狀態,還緊握住不釋放,就是極大的浪費。
在 Java13 中對其進行改進,包括:
可釋放空閑內存
支持的最大堆大小從 4TB 擴大到 16TB
我們來看下 ZGC 的內部邏輯。
ZGC 堆由一組稱為 ZPages 的堆區域組成,每個 ZPage 都與提交的堆內存的可變數量相關聯。當 ZGC 壓縮堆時,ZPages 被釋放并插入到頁面緩存 ZPageCache 中,頁面緩存中的 ZPages 可以重新使用,以滿足新的堆分配。
ZPageCache 中的 ZPages 集合代表堆中未使用的部分,這部分可以釋放回操作系統。ZPageCache 中的 ZPages 根據 LRU(最近最少使用)排序,并按照大中小進行分組。這樣的話就可以根據算法按順序釋放未使用的內存。
Java13 還提供了-XX:ZUncommitDelay=
在 Java13 中,ZGC 內存釋放功能默認開啟,可通過參數-XX:-ZUncommit關閉該功能。由于 ZGC 釋放內存時,不會低于最小堆內存,即當最小堆內存(-Xms)與最大堆內存(-Xmx)一樣時,不會自動釋放。
Socket API 重構
Java 中的 Socket 是從 Java1.0 開始就有的,是 Java 中不可或缺的網絡 API,算起來已經服役 20 多年了。在這段時間內,信息技術已經發生了很多變化,這些上古 API 有一定的局限性,而且不容易維護和調試。
Java 的 Socket API 主要包括java.net.ServerSocket和java.net.Socket,ServerSocket用來監聽連接請求的端口,連接成功后返回的是Socket對象,可以通過操作Socket對象實現數據發送和讀取。Java 是通過SocketImpl實現這些功能。
在 Java13 之前,通過SocketImpl的子類PlainSocketImpl實現。在 Java13 中,引入NioSocketImpl實現,該實現以 NIO 為基礎,與高速緩沖機制集成,實現非阻塞式網絡。
如果想用回PlainSocketImpl,可以設置啟動參數-Djdk.net.usePlainSocketImpl=true即可。
文末總結
本文介紹了 Java13 新增的特性,完整的特性清單可以從https://openjdk.java.net/projects/jdk/13/查看。后續內容會發布在 從小工到專家的 Java 進階之旅 系列專欄中。
青山不改,綠水長流,我們下次見。
推薦閱讀
一文掌握 Java8 Stream 中 Collectors 的 24 個操作
一文掌握 Java8 的 Optional 的 6 種操作
使用 Lambda 表達式實現超強的排序功能
Java8 的時間庫(1):介紹 Java8 中的時間類及常用 API
Java8 的時間庫(2):Date 與 LocalDate 或 LocalDateTime 互相轉換
Java8 的時間庫(3):開始使用 Java8 中的時間類
Java8 的時間庫(4):檢查日期字符串是否合法
Java8 的新特性
Java9 的新特性
Java10 的新特性
Java11 中基于嵌套關系的訪問控制優化
Java11 的新特性
Java12 的新特性
從小工到專家的 Java 進階之旅
你好,我是看山。游于碼界,戲享人生。如果文章對您有幫助,請、、關注。我還整理了一些精品學習資料,關注公眾號「看山的小屋」,回復“資料”即可獲得。
個人主頁:https://www.howardliu.cn
個人博文:Java 每半年就會更新一次新特性,再不掌握就要落伍了:Java13 的新特性
CSDN 主頁:https://kanshan.blog.csdn.net/
CSDN 博文:Java 每半年就會更新一次新特性,再不掌握就要落伍了:Java13 的新特性
Java Socket編程
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。