2017年8月,JCP執行委員會提出將Java的發佈頻率改成每六個月一次,新的發佈週期嚴格遵循時間點,將在每一年的3月份和9月份發佈。html
目前,JDK官網上已經能夠看到JDK 13的進展,最新版的JDK 13將於2019年9月17日發佈。java
目前,JDK13處於Release-Candidate Phase(發佈候選階段),將於9月17日正式發佈。目前該版本包含的特性已經所有固定,主要包含如下五個:編碼
JEP 350,Dynamic CDS Archivesspa
JEP 351,ZGC: Uncommit Unused Memory操作系統
JEP 353,Reimplement the Legacy Socket API.net
JEP 354: Switch Expressions (Preview)調試
JEP 355,Text Blocks (Preview)code
下面來逐一介紹下這五個重要的特性。orm
這一特性是在JEP310:Application Class-Data Sharing基礎上擴展而來的,Dynamic CDS Archives中的CDS指的就是Class-Data Sharing。htm
那麼,這個JEP310是個啥東西呢?
咱們知道在同一個物理機/虛擬機上啓動多個JVM時,若是每一個虛擬機都單獨裝載本身須要的全部類,啓動成本和內存佔用是比較高的。因此Java團隊引入了CDS的概念,經過把一些核心類在每一個JVM間共享,每一個JVM只須要裝載本身的應用類,啓動時間減小了,另外核心類是共享的,因此JVM的內存佔用也減小了。
CDS 只能做用於 Boot Class Loader 加載的類,不能做用於 App Class Loader 或者自定義的 Class Loader 加載的類。
在 Java 10 中,則將 CDS 擴展爲 AppCDS,顧名思義,AppCDS 不止可以做用於 Boot Class Loader了,App Class Loader 和自定義的 Class Loader 也都可以起做用,大大加大了 CDS 的適用範圍。也就說開發自定義的類也能夠裝載給多個JVM共享了。
Java 10中包含的JEP310的經過跨不一樣Java進程共享公共類元數據來減小了內存佔用和改進了啓動時間。
可是,JEP310中,使用AppCDS的過程仍是比較複雜的,須要有三個步驟:
一、決定要 Dump 哪些 Class 二、將類的內存 Dump 到歸檔文件中 三、使用 Dump 出來的歸檔文件加快應用啓動速度
這一次的JDK 13中的JEP 350 ,在JEP310的基礎上,又作了一些擴展。容許在Java應用程序執行結束時動態歸檔類,歸檔類將包括默認的基礎層 CDS(class data-sharing)存檔中不存在的全部已加載的應用程序類和庫類。
也就是說,在Java 13中再使用AppCDS的時候,就不在須要這麼複雜了。
在討論這個問題以前,想先問一個問題,JVM的GC釋放的內存會還給操做系統嗎?
GC後的內存如何處置,實際上是取決於不一樣的垃圾回收器的。由於把內存還給OS,意味着要調整JVM的堆大小,這個過程是比較耗費資源的。
在JDK 11中,Java引入了ZGC,這是一款可伸縮的低延遲垃圾收集器,可是當時只是實驗性的。而且,ZGC釋放的內存是不會還給操做系統的。
而在Java 13中,JEP 351再次對ZGC作了加強,本次 ZGC 能夠將未使用的堆內存返回給操做系統。之因此引入這個特性,是由於現在有不少場景中內存是比較昂貴的資源,在如下狀況中,將內存還給操做系統仍是頗有必要的:
使用易於維護和調試的更簡單、更現代的實現替換 java.net.Socket 和 java.net.ServerSocket API。
java.net.Socket和java.net.ServerSocket的實現很是古老,這個JEP爲它們引入了一個現代的實現。現代實現是Java 13中的默認實現,可是舊的實現尚未刪除,能夠經過設置系統屬性jdk.net.usePlainSocketImpl來使用它們。
運行一個實例化Socket和ServerSocket的類將顯示這個調試輸出。這是默認的(新的):
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就是新提供的實現。
若是使用舊的實現也是能夠的(指定參數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
上面的結果中,舊的實現java.net.PlainSocketImpl被用到了。
在JDK 12中引入了Switch表達式做爲預覽特性。JEP 354修改了這個特性,它引入了yield語句,用於返回值。這意味着,switch表達式(返回值)應該使用yield, switch語句(不返回值)應該使用break。
在之前,咱們想要在switch中返回內容,仍是比較麻煩的,通常語法以下:
int i; switch (x) { case "1": i=1; break; case "2": i=2; break; default: i = x.length(); break; }
在JDK13中使用如下語法:
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中就多了一個關鍵字用於跳出switch塊了,那就是yield,他用於返回一個值。和return的區別在於:return會直接跳出當前循環或者方法,而yield只會跳出當前switch塊。
在JDK 12中引入了Raw String Literals特性,但在發佈以前就放棄了。這個JEP在引入多行字符串文字(text block)在乎義上是相似的。
text block,文本塊,是一個多行字符串文字,它避免了對大多數轉義序列的須要,以可預測的方式自動格式化字符串,並在須要時讓開發人員控制格式。
咱們之前從外部copy一段文本串到Java中,會被自動轉義,若有一段如下字符串:
<html> <body> <p>Hello, world</p> </body> </html>
將其複製到Java的字符串中,會展現成如下內容:
"<html>\n" + " <body>\n" + " <p>Hello, world</p>\n" + " </body>\n" + "</html>\n";
即被自動進行了轉義,這樣的字符串看起來不是很直觀,在JDK 13中,就可使用如下語法了:
""" <html> <body> <p>Hello, world</p> </body> </html> """;
使用「」「做爲文本塊的開始符合結束符,在其中就能夠放置多行的字符串,不須要進行任何轉義。看起來就十分清爽了。
如常見的SQL語句:
String query = """ SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` WHERE `CITY` = 'INDIANAPOLIS' ORDER BY `EMP_ID`, `LAST_NAME`; """;
看起來就比較直觀,清爽了。
以上,就是JDK13中包含的5個特性,可以改變開發者的編碼風格的主要有Text Blocks和Switch Expressions兩個新特性,可是這兩個特性還處於預覽階段。
並且,JDK13並非LTS(長期支持)版本,若是你正在使用Java 8(LTS)或者Java 11(LTS),暫時能夠沒必要升級到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