2020年都在用Java13啦,看看都有哪些新特性吧

2017年8月,JCP執行委員會提出將Java的發佈頻率改爲每六個月一次,新的發佈週期嚴格遵循時間點,將在每年的3月份和9月份發佈。




目前該版本包含的特性已經全部固定,主要包含以下五個:

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)

下面來逐一介紹下這五個重要的特性。

Dynamic CDS Archives

這一特性是在JEP310:Application Class-Data Sharing 基礎上擴展而來的,Dynamic CDS Archives中的CDS指的就是Class-Data Sharing。

那麼,這個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的過程還是比較複雜的,需要有三個步驟:

1、決定要 Dump 哪些 Class

2、將類的內存 Dump 到歸檔文件中

3、使用 Dump 出來的歸檔文件加快應用啓動速度

這一次的JDK 13中的JEP 350 ,在JEP310的基礎上,又做了一些擴展。允許在Java應用程序執行結束時動態歸檔類,歸檔類將包括默認的基礎層 CDS(class data-sharing)存檔中不存在的所有已加載的應用程序類和庫類。

也就是說,在Java 13中再使用AppCDS的時候,就不在需要這麼複雜了。

ZGC: Uncommit Unused Memory

在討論這個問題之前,想先問一個問題,JVM的GC釋放的內存會還給操作系統嗎?

GC後的內存如何處置,其實是取決於不同的垃圾回收器的。因爲把內存還給OS,意味着要調整JVM的堆大小,這個過程是比較耗費資源的。

在JDK 11中,Java引入了ZGC,這是一款可伸縮的低延遲垃圾收集器,但是當時只是實驗性的。並且,ZGC釋放的內存是不會還給操作系統的。




而在Java 13中,JEP 351再次對ZGC做了增強,本次 ZGC 可以將未使用的堆內存返回給操作系統。之所以引入這個特性,是因爲如今有很多場景中內存是比較昂貴的資源,在以下情況中,將內存還給操作系統還是很有必要的:

  • 1、那些需要根據使用量付費的容器

  • 2、應用程序可能長時間處於空閒狀態並與許多其他應用程序共享或競爭資源的環境。

  • 3、應用程序在執行期間可能有非常不同的堆空間需求。例如,啓動期間所需的堆可能大於稍後在穩定狀態執行期間所需的堆。

  • 上海尚學堂官網這個沒什麼好說的,有從事多年的Java開發的高級教師及架構師爲大家帶來的最新版2020年針對企業,新研發出來的python,Java,大數據,人工智能等教學視頻及項目源碼及文檔!!

Reimplement the Legacy Socket API

使用易於維護和調試的更簡單、更現代的實現替換 java.net.Socket 和 java.net.ServerSocket API。

java.net.Socket和java.net.ServerSocket的實現非常古老,這個JEP爲它們引入了一個現代的實現。現代實現是Java 13中的默認實現,但是舊的實現還沒有刪除,可以通過設置系統屬性jdk.net.usePlainSocketImpl來使用它們。

運行一個實例化Socket和ServerSocket的類將顯示這個調試輸出。這是默認的(新的):

java-XX:+TraceClassLoadingJEP353|grepSocket
[0.033s][info][class,load]java.net.Socketsource:jrt:/java.base
[0.035s][info][class,load]java.net.SocketOptionssource:jrt:/java.base
[0.035s][info][class,load]java.net.SocketImplsource:jrt:/java.base
[0.039s][info][class,load]java.net.SocketImpl$$Lambda$1/0x0000000800b50840source:java.net.SocketImpl
[0.042s][info][class,load]sun.net.PlatformSocketImplsource:jrt:/java.base
[0.042s][info][class,load]sun.nio.ch.NioSocketImplsource:jrt:/java.base
[0.043s][info][class,load]sun.nio.ch.SocketDispatchersource:jrt:/java.base
[0.044s][info][class,load]java.net.DelegatingSocketImplsource:jrt:/java.base
[0.044s][info][class,load]java.net.SocksSocketImplsource:jrt:/java.base
[0.044s][info][class,load]java.net.ServerSocketsource:jrt:/java.base
[0.045s][info][class,load]jdk.internal.access.JavaNetSocketAccesssource:jrt:/java.base
[0.045s][info][class,load]java.net.ServerSocket$1source:jrt:/java.base

上面輸出的sun.nio.ch.NioSocketImpl就是新提供的實現。

如果使用舊的實現也是可以的(指定參數jdk.net.usePlainSocketImpl):

$java-Djdk.net.usePlainSocketImpl-XX:+TraceClassLoadingJEP353|grepSocket
[0.037s][info][class,load]java.net.Socketsource:jrt:/java.base
[0.039s][info][class,load]java.net.SocketOptionssource:jrt:/java.base
[0.039s][info][class,load]java.net.SocketImplsource:jrt:/java.base
[0.043s][info][class,load]java.net.SocketImpl$$Lambda$1/0x0000000800b50840source:java.net.SocketImpl
[0.046s][info][class,load]sun.net.PlatformSocketImplsource:jrt:/java.base
[0.047s][info][class,load]java.net.AbstractPlainSocketImplsource:jrt:/java.base
[0.047s][info][class,load]java.net.PlainSocketImplsource:jrt:/java.base
[0.047s][info][class,load]java.net.AbstractPlainSocketImpl$1source:jrt:/java.base
[0.047s][info][class,load]sun.net.ext.ExtendedSocketOptionssource:jrt:/java.base
[0.047s][info][class,load]jdk.net.ExtendedSocketOptionssource:jrt:/jdk.net
[0.047s][info][class,load]java.net.SocketOptionsource:jrt:/java.base
[0.047s][info][class,load]jdk.net.ExtendedSocketOptions$ExtSocketOptionsource:jrt:/jdk.net
[0.047s][info][class,load]jdk.net.SocketFlowsource:jrt:/jdk.net
[0.047s][info][class,load]jdk.net.ExtendedSocketOptions$PlatformSocketOptionssource:jrt:/jdk.net
[0.047s][info][class,load]jdk.net.ExtendedSocketOptions$PlatformSocketOptions$1source:jrt:/jdk.net
[0.048s][info][class,load]jdk.net.LinuxSocketOptionssource:jrt:/jdk.net
[0.048s][info][class,load]jdk.net.LinuxSocketOptions$$Lambda$2/0x0000000800b51040source:jdk.net.LinuxSocketOptions
[0.049s][info][class,load]jdk.net.ExtendedSocketOptions$1source:jrt:/jdk.net
[0.049s][info][class,load]java.net.StandardSocketOptionssource:jrt:/java.base
[0.049s][info][class,load]java.net.StandardSocketOptions$StdSocketOptionsource:jrt:/java.base
[0.051s][info][class,load]sun.net.ext.ExtendedSocketOptions$$Lambda$3/0x0000000800b51440source:sun.net.ext.ExtendedSocketOptions
[0.057s][info][class,load]java.net.DelegatingSocketImplsource:jrt:/java.base
[0.057s][info][class,load]java.net.SocksSocketImplsource:jrt:/java.base
[0.058s][info][class,load]java.net.ServerSocketsource:jrt:/java.base
[0.058s][info][class,load]jdk.internal.access.JavaNetSocketAccesssource:jrt:/java.base
[0.058s][info][class,load]java.net.ServerSocket$1source:jrt:/java.base

Switch Expressions (Preview)


在JDK 12中引入了Switch表達式作爲預覽特性。JEP 354修改了這個特性,它引入了yield語句,用於返回值。這意味着,switch表達式(返回值)應該使用yield, switch語句(不返回值)應該使用break。

在以前,我們想要在switch中返回內容,還是比較麻煩的,一般語法如下:

inti;
switch(x){
case"1":
i=1;
break;
case"2":
i=2;
break;
default:
i=x.length();
break;
}

在JDK13中使用以下語法:

inti=switch(x){
case"1"->1;
case"2"->2;
default->{
intlen=args[1].length();
yieldlen;
}
};

或者

inti=switch(x){
case"1":yield1;
case"2":yield2;
default:{
intlen=args[1].length();
yieldlen;
}
};

在這之後,switch中就多了一個關鍵字用於跳出switch塊了,那就是yield,他用於返回一個值。和return的區別在於:return會直接跳出當前循環或者方法,而yield只會跳出當前switch塊。


Text Blocks (Preview)

在JDK 12中引入了Raw String Literals特性,但在發佈之前就放棄了。這個JEP在引入多行字符串文字(text block)在意義上是類似的。

text block,文本塊,是一個多行字符串文字,它避免了對大多數轉義序列的需要,以可預測的方式自動格式化字符串,並在需要時讓開發人員控制格式。

我們以前從外部copy一段文本串到Java中,會被自動轉義,如有一段以下字符串:

<html>
<body>
<p>Hello,Hollis</p>
</body>
</html>

將其複製到Java的字符串中,會展示成以下內容:

"<html>\n"+
"<body>\n"+
"<p>Hello,Hollis</p>\n"+
"</body>\n"+
"</html>\n";

即被自動進行了轉義,這樣的字符串看起來不是很直觀,在JDK 13中,就可以使用以下語法了:

"""
<html>
<body>
<p>Hello,Hollis</p>
</body>
</html>
""";

使用"""作爲文本塊的開始符合結束符,在其中就可以放置多行的字符串,不需要進行任何轉義。看起來就十分清爽了。

如常見的SQL語句:

Stringquery="""
SELECT`EMP_ID`,`LAST_NAME`FROM`EMPLOYEE_TB`
WHERE`CITY`='INDIANAPOLIS'
ORDERBY`EMP_ID`,`LAST_NAME`;
""";

看起來就比較直觀,清爽了。

總結

以上,就是JDK13中包含的5個特性,能夠改變開發者的編碼風格的主要有Text Blocks和Switch Expressions兩個新特性,但是這兩個特性還處於預覽階段。

而且,JDK13並不是LTS(長期支持)版本,如果你正在使用Java 8(LTS)或者Java 11(LTS),暫時可以不必升級到Java 13。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章