JDK 13 于 2019 年 9 月 17 日正式發(fā)布。
新版本主要包含五個(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)
Dynamic CDS Archives(動(dòng)態(tài) CDS 歸檔)
首先介紹一下 CDS,CDS 全名為 Class Data Sharing,目的是減少Java編程語(yǔ)言應(yīng)用程序的啟動(dòng)時(shí)間,特別是較小的應(yīng)用程序,并減少內(nèi)存占用。實(shí)現(xiàn)思路是通過(guò)JVM調(diào)用期間,將共享的歸檔文件被映射到內(nèi)存中,從而節(jié)省了加載這些類(lèi)的成本,并允許多個(gè) JVM 進(jìn)程共享這些類(lèi)的大部分 JVM 元數(shù)據(jù)。
JVM 中 CDS 的歷史
- JDK 1.5 引入了CDS 的概念,通過(guò)把 rt.jar 中的核心類(lèi)提前轉(zhuǎn)化成內(nèi)部表示,轉(zhuǎn)儲(chǔ)到一個(gè)共享存檔(shared archive)中。每個(gè) JVM 只需要裝載自己的應(yīng)用類(lèi),啟動(dòng)時(shí)間減少了,另外核心類(lèi)是共享的,所以 JVM 的內(nèi)存占用也減少了;
- Oracle JDK 9 中,在支持其他 GC 算法和應(yīng)用程序類(lèi)的情況下,這變得非常有用;
- JDK 10 之前,它一直是一個(gè)商業(yè)特性,在JDK 10 中它成為了開(kāi)源的;
- OpenJDK 13 / JDK 13 中實(shí)現(xiàn)了動(dòng)態(tài) CDS 歸檔,提高應(yīng)用程序類(lèi)數(shù)據(jù)共享(AppCDS)的可用性。消除了用戶為每個(gè)應(yīng)用程序創(chuàng)建類(lèi)列表而進(jìn)行試運(yùn)行的需要。當(dāng)程序存在時(shí),可以使用 -XX:ArchiveClassesAtExit=<filename>,而不是提供類(lèi)列表。然后使用 -XX:SharedArchiveFile=<filename>,可以在 JDK 的系統(tǒng)默認(rèn)存檔之上共享類(lèi)數(shù)據(jù)
ZGC: Uncommit Unused Memory
ZGC 是在 JDK 11 中引入的,但是到目前為止它還沒(méi)有像 G1 垃圾收集器那樣將未使用的堆內(nèi)存返回到操作系統(tǒng)。這個(gè) JEP 解決了這個(gè)問(wèn)題,并且默認(rèn)啟用了這個(gè)功能。
Reimplement the Legacy Socket API
java.net.Socket 和 java.net.ServerSocket 的實(shí)現(xiàn)非常古老,這個(gè) JEP 為它們引入了新的實(shí)現(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)使用它們。但沒(méi)有為 java.net.DatagramSocket 引入新的實(shí)現(xiàn)。
運(yùn)行一個(gè)實(shí)例化 Socket 和 ServerSocket 的類(lèi)將顯示這個(gè)調(diào)試輸出。這是默認(rèn)的(新的實(shí)現(xià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)。
現(xiàn)在讓我們?cè)O(shè)置系統(tǒng)屬性并再次運(yùn)行:
$ 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
它顯示了現(xiàn)在使用的舊的實(shí)現(xiàn) java.net.PlainSocketImpl。
Switch Expressions (Preview)
在 JDK 12 中引入了 Switch 表達(dá)式作為預(yù)覽特性。JEP 354 修改了這個(gè)特性,它引入了 yield 語(yǔ)句來(lái)從塊中返回值,而不是使用 break。這意味著,switch 表達(dá)式(返回值)應(yīng)該使用 yield,而 switch 語(yǔ)句(不返回值)應(yīng)該使用 break。
JDK 13 之前的 Switch 的寫(xiě)法:
int i;
switch (x) {
case "1":
i = 1;
break;
case "2":
i = 2;
break;
default:
i = x.length();
break;
}
JDK 13 的 Switch 的寫(xiě)法:
switch (x) {
case "1" -> 1;
case "2" -> 2;
default -> {
int len = x.length();
yield len;
}
}
或者
switch (x) {
case "1": yield 1;
case "2": yield 2;
default: {
int len = x.length();
yield len;
}
}
Text Blocks (Preview)
JDK 12 中引入了 Raw String Literals 特性,但在發(fā)布之前就放棄了。JEP 在引入多行字符串文字(一個(gè)文本塊)方面與此類(lèi)似。
HTML 例子:
使用字符串文字:
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
使用文本塊:
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
SQL 例子
使用字符串文字:
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
"WHERE `CITY` = 'INDIANAPOLIS'\n" +
"ORDER BY `EMP_ID`, `LAST_NAME`;\n";
使用文本塊:
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";
總結(jié):
以上,就是 JDK 13 中包含的 5 個(gè)新特性,能夠改變開(kāi)發(fā)者編碼風(fēng)格的主要有 Text Blocks 和 Switch Expressions 兩個(gè)新特性,但是這兩個(gè)特性還處于預(yù)覽階段。
而且,JDK 13 并不是 LTS(長(zhǎng)期支持)版本,如果你正在使用 Java 8(LTS)或者 Java 11(LTS),暫時(shí)可以不必升級(jí)到 Java 13。
想了解更多技術(shù)文章,請(qǐng)關(guān)注我的公眾號(hào):TomScript,獲得獨(dú)家整理的學(xué)習(xí)資源和日常干貨推送。