Java 17 將要發布,補一下 Java 13 中的新功能


點贊再看,動力無限。Hello world : ) 微信搜「 程序猿阿朗 」。

本文 Github.com/niumoo/JavaNotes未讀代碼博客 已經收錄,有很多知識點和系列文章。

本文章屬於 Java 新特性教程 系列,已經收錄在 Github.com/niumoo/JavaNotes ,點個贊,不迷路。

Java 13 by Alena Penkova

自從 Oracle 調整了 Java 的版本發布節奏之后,Java 版本發布越來越快,雖然都說 Java 版本任他發,我用 Java 8,不過新版本的 Java 功能還是要學習一下的。

Java 13 早在 2019 年 9 月就已經發布,雖然不是長久支持版本,但是也帶來了不少新功能。

Java 13 官方下載:https://jdk.java.net/archive/

Java 13 官方文檔:http://openjdk.java.net/projects/jdk/13/

Java 13 新功能

  1. JEP 350: 動態 CDS 存檔
  2. JEP 351: ZGC,歸還未使用的內存 (實驗性)
  3. JEP 353: 重新實現 Socket API
  4. JEP 354: Switch 表達式 (二次預覽)
  5. JEP 355: 文本塊 (預覽)

擴展:此文章屬於 Java 新特性教程 系列,會介紹 Java 每個版本的新功能,可以點擊瀏覽。

1. JEP 350 動態 CDS 存檔

JVM 啟動時有一步是需要在內存中加載類,而如果有多個 jar,加載第一個 jar 的速度是最慢的。這就延長了程序的啟動時間,為了減少這個時間,Java 10 引入了應用程序類數據共享(CDS)機制,它可以把你想共享的類共享在程序之間,使不同的 Java 進程之間共享這個類來減少這個類占用的空間以及加載速度。不過 Java 10 中使用這個功能的步驟比較繁瑣。

擴展閱讀:Java 10 新功能介紹

而 Java 13 中的 AppCDS,允許 Java 應用在程序執行結束時(如果 JVM 沒有崩潰)進行動態存檔;存儲的內容包括所有加載的應用類型類和使用的類庫,這些存儲的類庫本來並不存在於默認的 CDS 存檔中。

使用這個功能非常簡單,只需要在程序啟動時增加啟動參數 。

# ArchiveClassesAtExit,程序結束時動態存檔
bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello
# SharedArchiveFile,使用指定存檔啟動
bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello

2. JEP 351: ZGC,歸還未使用的內存 (實驗性)

在 Java 13 之前,ZGC 雖然在清理內存時導致的停頓時間非常少,但是即使內存已經長時間沒有使用,ZGC 也不會將內存返還給操作系統,這對那些十分關注內存占用的應用程序非常不友好。

比如:

  • 資源按使用量付費的雲上容器環境。

  • 應用雖然長時間閑置,但是占用了內存,導致運行的其他程序內存緊張。

而新增的這個功能,可以讓 ZGC 歸還長時間沒有使用的內存給操作系統,這對某些用戶來說十分友好。

3. JEP 353: 重新實現 Socket API

java.net.Socketjava.net.ServerSocket 類早在 Java 1.0 時就已經引入了,它們的實現的 Java 代碼和 C 語言代碼的混合,維護和調試都十分不易;而且這個實現還存在並發問題,有時候排查起來也很困難。

因此,在 Java 13 中引入了新的實現方式,使用了新的實現 NioSocketImpl 來代替老舊的 PlainSocketImpl 實現。雖然功能相同,但是老的方式在當前以及未來幾個版本內不會刪除,用戶隨時可以通過 -Djdk.net.usePlainSocketImpl 參數切換回老的實現方式,以兼容意外情況。

編寫一個測試類可以發現這個變化。

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Test {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8000)){
            boolean running = true;
            while(running){
                Socket clientSocket = serverSocket.accept();
                //do something with clientSocket
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用 Java 13 運行,通過參數 -XX:+TraceClassLoading 追蹤加載的類,日志中可以看到 NioSocketImpl

➜  develop ./jdk-13.0.2.jdk/Contents/Home/bin/java -XX:+TraceClassLoading Test.java | grep SocketImpl
[0.699s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.699s][info   ][class,load] java.net.SocketImpl$$Lambda$173/0x0000000800c37440 source: java.net.SocketImpl
[0.702s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base
[0.702s][info   ][class,load] sun.nio.ch.NioSocketImpl source: jrt:/java.base
[0.713s][info   ][class,load] sun.nio.ch.NioSocketImpl$FileDescriptorCloser source: jrt:/java.base

但在 Java 12 並不是 NioSocketImpl

➜  develop ./jdk-12.0.2.jdk/Contents/Home/bin/java -XX:+TraceClassLoading Test.java | grep SocketImpl
[0.665s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.665s][info   ][class,load] java.net.AbstractPlainSocketImpl source: jrt:/java.base
[0.665s][info   ][class,load] java.net.PlainSocketImpl source: jrt:/java.base
[0.665s][info   ][class,load] java.net.SocksSocketImpl source: jrt:/java.base
[0.666s][info   ][class,load] java.net.AbstractPlainSocketImpl$1 source: jrt:/java.base

4. JEP 354: Switch 表達式 (二次預覽)

你為什么不願意使用使用 switch 表達式?我想其中一個原因應該是, switch 表達式的代碼不夠美觀優雅,甚至有些啰嗦。比如像下面的例子。

package com.wdbyte;

public class Java13Switch {
    public static void main(String[] args) {
      //通過傳入月份,輸出月份所屬的季節
      System.out.println(switchJava12Before("march"));
    }
    public static String switchJava12Before(String month) {
        String reuslt = null;
        switch (month) {
            case "march":
            case "april":
            case "may":
                reuslt = "春天";
                break;
            case "june":
            case "july":
            case "august":
                reuslt = "夏天";
                break;
            case "september":
            case "october":
            case "november":
                reuslt = "秋天";
                break;
            case "december":
            case "january":
            case "february":
                reuslt = "冬天";
                break;
        }
        return reuslt;
    }
}

而在 Java 12 中,已經對 switch 進行了改進,使之可以使用 cast L -> 表達式進行操作,且可以具有返回值,這樣代碼就更加美觀使用了,不過這在 Java 12 中是一個預覽功能。

// 通過傳入月份,輸出月份所屬的季節
public static String switchJava12(String month) {
     return switch (month) {
        case "march", "april", "may"            -> "春天";
        case "june", "july", "august"           -> "夏天";
        case "september", "october", "november" -> "秋天";
        case "december", "january", "february"  -> "冬天";
        default -> "month erro";
    };
}

擴展閱讀:Java 12 新特性介紹JEP 325: Switch 表達式

而現在,在 Java 13 中,又對 switch 表達式進行了增強,增加了yield 關鍵詞用於返回值,相比 break ,語義更加明確了。

public static String switchJava13(String month) {
    return switch (month) {
        case "march", "april", "may":
            yield "春天";
        case "june", "july", "august":
            yield "夏天";
        case "september", "october", "november":
            yield "秋天";
        case "december", "january", "february":
            yield "冬天";
        default:
            yield "month error";
    };
}

5. JEP 355: 文本塊 (預覽)

在這之前,如果我們把一個 JSON 賦值給字符串:

String content = "{\n"
    + "    \"upperSummary\": null,\n"
    + "    \"sensitiveTypeList\": null,\n"
    + "    \"gmtModified\": \"2011-08-05 10:50:09\",\n"
    + "    \"lowerGraph\": null,\n"
    + "    \"signature\": \"\",\n"
    + "    \"appName\": \"xxx\",\n"
    + "    \"lowerSummary\": null,\n"
    + "    \"gmtCreate\": \"2011-08-05 10:50:09\",\n"
    + "    \"type\": \"CALL\",\n"
    + "    \"name\": \"xxxx\",\n"
    + "    \"subType\": \"yyy\",\n"
    + "    \"id\": 1,\n"
    + "    \"projectId\": 1,\n"
    + "    \"status\": 1\n"
    + "}";

終於不用寫丑陋的長字符串了,從 Java 13 開始你可以使用文本塊的方式定義字符串了。

String content2 = """
        {
        "upperSummary": null,
        "sensitiveTypeList": null,
        "gmtModified": "2011-08-05 10:50:09",
        "lowerGraph": null,
        "signature": "",
        "appName": "xxx",
        "lowerSummary": null,
        "gmtCreate": "2011-08-05 10:50:09",
        "type": "CALL",
        "name": "xxxx",
        "subType": "yyy",
        "id": 1,
        "projectId": 1,
        "status": 1
    }
                 """;

不過這是一個預覽功能,如果你要是在 Java 13 中使用需要手動開啟預覽功能,這個功能在 Java 15 中正式發布。

如果你想嘗試,可以去下載最新版了,玩的開心。

參考

  1. http://openjdk.java.net/projects/jdk/13/
  2. https://nipafx.dev/java-application-class-data-sharing/
  3. https://www.wdbyte.com/2020/02/jdk/jdk12-feature/
  4. https://mkyong.com/java/what-is-new-in-java-13/
  5. Java 新特性教程

相關閱讀

<完>

Hello world : ) 我是阿朗,一線技術工具人,認認真真寫文章。

點贊的個個都是人才,不僅長得帥氣好看,說話還好聽。


文章持續更新,可以關注公眾號「 程序猿阿朗 」或訪問「未讀代碼博客 」。

回復【資料】有我准備的各系列知識點和必看書籍。

本文 Github.com/niumoo/JavaNotes 已經收錄,有很多知識點和系列文章,歡迎Star。

等你好久


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM