Java13 明天發(fā)布(最新最全新特性解讀)
2017年8月,JCP執(zhí)行委員會(huì)提出將Java的發(fā)布頻率改為每六個(gè)月一次,新的發(fā)布周期嚴(yán)格遵循時(shí)間點(diǎn),將在每年的3月份和9月份發(fā)布。
目前,JDK官網(wǎng)上已經(jīng)可以看到JDK 13的進(jìn)展,最新版的JDK 13將于2019年9月17日發(fā)布。
目前,JDK13處于Release-Candidate Phase(發(fā)布候選階段),將于9月17日正式發(fā)布。目前該版本包含的特性已經(jīng)全部固定,主要包含以下五個(gè):
JEP 350,Dynamic CDS Archives
JEP 351,ZGC: Uncommit Unused Memory
JEP 353,Reimplement the Legacy Socket API
JEP 354: Switch Expressions (Preview)
JEP 355,Text Blocks (Preview)
下面來(lái)逐一介紹下這五個(gè)重要的特性。
Dynamic CDS Archives
這一特性是在JEP310:Application Class-Data Sharing基礎(chǔ)上擴(kuò)展而來(lái)的,Dynamic CDS Archives中的CDS指的就是Class-Data Sharing。
那么,這個(gè)JEP310是個(gè)啥東西呢?
我們知道在同一個(gè)物理機(jī)/虛擬機(jī)上啟動(dòng)多個(gè)JVM時(shí),如果每個(gè)虛擬機(jī)都單獨(dú)裝載自己需要的所有類,啟動(dòng)成本和內(nèi)存占用是比較高的。所以Java團(tuán)隊(duì)引入了CDS的概念,通過(guò)把一些核心類在每個(gè)JVM間共享,每個(gè)JVM只需要裝載自己的應(yīng)用類,啟動(dòng)時(shí)間減少了,另外核心類是共享的,所以JVM的內(nèi)存占用也減少了。
CDS 只能作用于 Boot Class Loader 加載的類,不能作用于 App Class Loader 或者自定義的 Class Loader 加載的類。
在 Java 10 中,則將 CDS 擴(kuò)展為 AppCDS,顧名思義,AppCDS 不止能夠作用于 Boot Class Loader了,App Class Loader 和自定義的 Class Loader 也都能夠起作用,大大加大了 CDS 的適用范圍。也就說(shuō)開(kāi)發(fā)自定義的類也可以裝載給多個(gè)JVM共享了。
Java 10中包含的JEP310的通過(guò)跨不同Java進(jìn)程共享公共類元數(shù)據(jù)來(lái)減少了內(nèi)存占用和改進(jìn)了啟動(dòng)時(shí)間。
但是,JEP310中,使用AppCDS的過(guò)程還是比較復(fù)雜的,需要有三個(gè)步驟:
1、決定要 Dump 哪些 Class
2、將類的內(nèi)存 Dump 到歸檔文件中
3、使用 Dump 出來(lái)的歸檔文件加快應(yīng)用啟動(dòng)速度
這一次的JDK 13中的JEP 350 ,在JEP310的基礎(chǔ)上,又做了一些擴(kuò)展。允許在Java應(yīng)用程序執(zhí)行結(jié)束時(shí)動(dòng)態(tài)歸檔類,歸檔類將包括默認(rèn)的基礎(chǔ)層 CDS(class data-sharing)存檔中不存在的所有已加載的應(yīng)用程序類和庫(kù)類。
也就是說(shuō),在Java 13中再使用AppCDS的時(shí)候,就不在需要這么復(fù)雜了。
ZGC: Uncommit Unused Memory
在討論這個(gè)問(wèn)題之前,想先問(wèn)一個(gè)問(wèn)題,JVM的GC釋放的內(nèi)存會(huì)還給操作系統(tǒng)嗎?
GC后的內(nèi)存如何處置,其實(shí)是取決于不同的垃圾回收器的。因?yàn)榘褍?nèi)存還給OS,意味著要調(diào)整JVM的堆大小,這個(gè)過(guò)程是比較耗費(fèi)資源的。
在JDK 11中,Java引入了ZGC,這是一款可伸縮的低延遲垃圾收集器,但是當(dāng)時(shí)只是實(shí)驗(yàn)性的。并且,ZGC釋放的內(nèi)存是不會(huì)還給操作系統(tǒng)的。
而在Java 13中,JEP 351再次對(duì)ZGC做了增強(qiáng),本次 ZGC 可以將未使用的堆內(nèi)存返回給操作系統(tǒng)。之所以引入這個(gè)特性,是因?yàn)槿缃裼泻芏鄨?chǎng)景中內(nèi)存是比較昂貴的資源,在以下情況中,將內(nèi)存還給操作系統(tǒng)還是很有必要的:
1、那些需要根據(jù)使用量付費(fèi)的容器
2、應(yīng)用程序可能長(zhǎng)時(shí)間處于空閑狀態(tài)并與許多其他應(yīng)用程序共享或競(jìng)爭(zhēng)資源的環(huán)境。
3、應(yīng)用程序在執(zhí)行期間可能有非常不同的堆空間需求。例如,啟動(dòng)期間所需的堆可能大于稍后在穩(wěn)定狀態(tài)執(zhí)行期間所需的堆。
Reimplement the Legacy Socket API
使用易于維護(hù)和調(diào)試的更簡(jiǎn)單、更現(xiàn)代的實(shí)現(xiàn)替換 java.net.Socket 和 java.net.ServerSocket API。
java.net.Socket和java.net.ServerSocket的實(shí)現(xiàn)非常古老,這個(gè)JEP為它們引入了一個(gè)現(xiàn)代的實(shí)現(xiàn)?,F(xiàn)代實(shí)現(xiàn)是Java 13中的默認(rèn)實(shí)現(xiàn),但是舊的實(shí)現(xiàn)還沒(méi)有刪除,可以通過(guò)設(shè)置系統(tǒng)屬性jdk.net.usePlainSocketImpl來(lái)使用它們。
運(yùn)行一個(gè)實(shí)例化Socket和ServerSocket的類將顯示這個(gè)調(diào)試輸出。這是默認(rèn)的(新的):
java -XX: TraceClassLoading JEP353 | grep Socket [0.033s][info ][class,load] java.net.Socket source: jrt:/java.base [0.035s][info ][class,load] java.net.SocketOptions source: jrt:/java.base [0.035s][info ][class,load] java.net.SocketImpl source: jrt:/java.base [0.039s][info ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800b50840 source: java.net.SocketImpl [0.042s][info ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base [0.042s][info ][class,load] sun.nio.ch.NioSocketImpl source: jrt:/java.base [0.043s][info ][class,load] sun.nio.ch.SocketDispatcher source: jrt:/java.base [0.044s][info ][class,load] java.net.DelegatingSocketImpl source: jrt:/java.base [0.044s][info ][class,load] java.net.SocksSocketImpl source: jrt:/java.base [0.044s][info ][class,load] java.net.ServerSocket source: jrt:/java.base [0.045s][info ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base [0.045s][info ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
上面輸出的sun.nio.ch.NioSocketImpl就是新提供的實(shí)現(xiàn)。
如果使用舊的實(shí)現(xiàn)也是可以的(指定參數(shù)jdk.net.usePlainSocketImpl):
$ java -Djdk.net.usePlainSocketImpl -XX: TraceClassLoading JEP353 | grep Socket [0.037s][info ][class,load] java.net.Socket source: jrt:/java.base [0.039s][info ][class,load] java.net.SocketOptions source: jrt:/java.base [0.039s][info ][class,load] java.net.SocketImpl source: jrt:/java.base [0.043s][info ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800b50840 source: java.net.SocketImpl [0.046s][info ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base [0.047s][info ][class,load] java.net.AbstractPlainSocketImpl source: jrt:/java.base [0.047s][info ][class,load] java.net.PlainSocketImpl source: jrt:/java.base [0.047s][info ][class,load] java.net.AbstractPlainSocketImpl$1 source: jrt:/java.base [0.047s][info ][class,load] sun.net.ext.ExtendedSocketOptions source: jrt:/java.base [0.047s][info ][class,load] jdk.net.ExtendedSocketOptions source: jrt:/jdk.net [0.047s][info ][class,load] java.net.SocketOption source: jrt:/java.base [0.047s][info ][class,load] jdk.net.ExtendedSocketOptions$ExtSocketOption source: jrt:/jdk.net [0.047s][info ][class,load] jdk.net.SocketFlow source: jrt:/jdk.net [0.047s][info ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions source: jrt:/jdk.net [0.047s][info ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions$1 source: jrt:/jdk.net [0.048s][info ][class,load] jdk.net.LinuxSocketOptions source: jrt:/jdk.net [0.048s][info ][class,load] jdk.net.LinuxSocketOptions$$Lambda$2/0x0000000800b51040 source: jdk.net.LinuxSocketOptions [0.049s][info ][class,load] jdk.net.ExtendedSocketOptions$1 source: jrt:/jdk.net [0.049s][info ][class,load] java.net.StandardSocketOptions source: jrt:/java.base [0.049s][info ][class,load] java.net.StandardSocketOptions$StdSocketOption source: jrt:/java.base [0.051s][info ][class,load] sun.net.ext.ExtendedSocketOptions$$Lambda$3/0x0000000800b51440 source: sun.net.ext.ExtendedSocketOptions [0.057s][info ][class,load] java.net.DelegatingSocketImpl source: jrt:/java.base [0.057s][info ][class,load] java.net.SocksSocketImpl source: jrt:/java.base [0.058s][info ][class,load] java.net.ServerSocket source: jrt:/java.base [0.058s][info ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base [0.058s][info ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
上面的結(jié)果中,舊的實(shí)現(xiàn)java.net.PlainSocketImpl被用到了。
Switch Expressions (Preview)
在JDK 12中引入了Switch表達(dá)式作為預(yù)覽特性。JEP 354修改了這個(gè)特性,它引入了yield語(yǔ)句,用于返回值。這意味著,switch表達(dá)式(返回值)應(yīng)該使用yield, switch語(yǔ)句(不返回值)應(yīng)該使用break。
在以前,我們想要在switch中返回內(nèi)容,還是比較麻煩的,一般語(yǔ)法如下:
int i; switch (x) { case "1": i=1; break; case "2": i=2; break; default: i = x.length(); break; }
在JDK13中使用以下語(yǔ)法:
int i = switch (x) { case "1" -> 1; case "2" -> 2; default -> { int len = args[1].length(); yield len; } };
或者
int i = switch (x) { case "1": yield 1; case "2": yield 2; default: { int len = args[1].length(); yield len; } };
在這之后,switch中就多了一個(gè)關(guān)鍵字用于跳出switch塊了,那就是yield,他用于返回一個(gè)值。和return的區(qū)別在于:return會(huì)直接跳出當(dāng)前循環(huán)或者方法,而yield只會(huì)跳出當(dāng)前switch塊。
Text Blocks (Preview)
在JDK 12中引入了Raw String Literals特性,但在發(fā)布之前就放棄了。這個(gè)JEP在引入多行字符串文字(text block)在意義上是類似的。
text block,文本塊,是一個(gè)多行字符串文字,它避免了對(duì)大多數(shù)轉(zhuǎn)義序列的需要,以可預(yù)測(cè)的方式自動(dòng)格式化字符串,并在需要時(shí)讓開(kāi)發(fā)人員控制格式。
我們以前從外部copy一段文本串到Java中,會(huì)被自動(dòng)轉(zhuǎn)義,如有一段以下字符串:
<html> <body> <p>Hello, world</p> </body> </html>
將其復(fù)制到Java的字符串中,會(huì)展示成以下內(nèi)容:
"<html>\n" " <body>\n" " <p>Hello, world</p>\n" " </body>\n" "</html>\n";
即被自動(dòng)進(jìn)行了轉(zhuǎn)義,這樣的字符串看起來(lái)不是很直觀,在JDK 13中,就可以使用以下語(yǔ)法了:
""" <html> <body> <p>Hello, world</p> </body> </html> """;
使用“”“作為文本塊的開(kāi)始符合結(jié)束符,在其中就可以放置多行的字符串,不需要進(jìn)行任何轉(zhuǎn)義??雌饋?lái)就十分清爽了。
如常見(jiàn)的SQL語(yǔ)句:
String query = """ SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` WHERE `CITY` = 'INDIANAPOLIS' ORDER BY `EMP_ID`, `LAST_NAME`; """;
看起來(lái)就比較直觀,清爽了。
總結(jié)
以上,就是JDK13中包含的5個(gè)特性,能夠改變開(kāi)發(fā)者的編碼風(fēng)格的主要有Text Blocks和Switch Expressions兩個(gè)新特性,但是這兩個(gè)特性還處于預(yù)覽階段。
而且,JDK13并不是LTS(長(zhǎng)期支持)版本,如果你正在使用Java 8(LTS)或者Java 11(LTS),暫時(shí)可以不必升級(jí)到Java 13.
參考資料:
https://openjdk.java.net/projects/jdk/13/
https://metebalci.com/blog/what-is-new-in-java-13/
https://www.jianshu.com/p/890196bf529a
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java8新特性 獲取list某一列的操作
- Java8新特性之新日期時(shí)間庫(kù)的使用教程
- Java8新特性:Lambda表達(dá)式之方法引用詳解
- java8新特性之stream的collect實(shí)戰(zhàn)教程
- java8新特性 stream流的方式遍歷集合和數(shù)組操作
- 詳細(xì)分析JAVA8新特性 Base64
- Java8新特性Stream的完全使用指南
- Java中JDK14的新特性之JFR,JMC和JFR事件流(推薦)
- Java8新特性時(shí)間日期庫(kù)DateTime API及示例詳解
- 詳解Java8新特性Stream之list轉(zhuǎn)map及問(wèn)題解決
- Java10新特性解讀
相關(guān)文章
Spring?Boot請(qǐng)求處理之常用參數(shù)注解使用教程
這篇文章主要給大家介紹了關(guān)于Spring?Boot請(qǐng)求處理之常用參數(shù)注解使用的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-03-03Spring?Security使用數(shù)據(jù)庫(kù)登錄認(rèn)證授權(quán)
本文主要介紹了Spring?Security使用數(shù)據(jù)庫(kù)登錄認(rèn)證授權(quán),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01Eclipse Web項(xiàng)目打成war包的方法圖解
當(dāng)Tomcat啟動(dòng)后該壓縮文件自動(dòng)解壓縮,war包方便了web工程的發(fā)布,那么Eclipse中如何將Web項(xiàng)目打成war包呢?下面小編通過(guò)圖文并茂的方式給大家講解下Eclipse Web項(xiàng)目打成war包的方法,一起看看吧2016-08-08java:無(wú)法訪問(wèn)org.springframework.boot.SpringApplication的解決方法
這篇文章主要給大家介紹了關(guān)于java:無(wú)法訪問(wèn)org.springframework.boot.SpringApplication的解決方法,文中通過(guò)實(shí)例代碼將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01httpclient getPoolEntryBlocking連接池方法源碼解讀
這篇文章主要為大家介紹了httpclient getPoolEntryBlocking連接池方法源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Java實(shí)現(xiàn)音頻轉(zhuǎn)文本的示例代碼(語(yǔ)音識(shí)別)
Java中實(shí)現(xiàn)音頻轉(zhuǎn)文本通常涉及使用專門(mén)的語(yǔ)音識(shí)別服務(wù),本文主要介紹了Java實(shí)現(xiàn)音頻轉(zhuǎn)文本的示例代碼(語(yǔ)音識(shí)別),具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05GSON實(shí)現(xiàn)Java對(duì)象的JSON序列化與反序列化的實(shí)例教程
GSON是Google開(kāi)發(fā)并開(kāi)源的一個(gè)Java的JSON轉(zhuǎn)換庫(kù),這里我們將來(lái)講解GSON實(shí)現(xiàn)Java對(duì)象的JSON序列化與反序列化的實(shí)例教程,需要的朋友可以參考下2016-06-06