超詳細 Java 15 新功能介紹

程式猿阿朗發表於2021-08-17

點贊再看,動力無限。微信搜「 程式猿阿朗 」,認認真真寫文章。

本文 Github.com/niumoo/JavaNotes未讀程式碼部落格 已經收錄,有很多知識點和系列文章。

Java 15 在 2020 年 9 月釋出,雖然不是長久支援版本,但是也帶來了 14 個新功能,這些新功能中有不少是十分實用的。

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

Java 15 官方文件:https://openjdk.java.net/projects/jdk/15/

Java 15 新功能:

JEP 描述
JEP 339 愛德華曲線演算法(EdDSA)
JEP 360 Sealed Classes(密封類)預覽
JEP 371 Hidden Classes(隱藏類)
JEP 372 移除 Nashorn JavaScript 引擎
JEP 373 重新實現 DatagramSocket APII
JEP 374 禁用和廢棄偏向鎖(Biased Locking)
JEP 375 instanceof 型別匹配 (二次預覽)
JEP 377 ZGC: 可擴充套件低延遲垃圾收集器(正式釋出)
JEP 378 文字塊
JEP 379 Shenandoah: 低停頓時間的垃圾收集器
JEP 381 刪除 Solaris 和 SPARC 埠
JEP 383 外部記憶體訪問 API(第二個孵化器))
JEP 384 Records (二次預覽)
JEP 385 廢棄 RMI 啟用機制

1. JEP 339 愛德華曲線演算法(EdDSA)

Java 15 中增加了一個新的密碼學演算法,愛德華曲線演算法(EdDSA)簽名演算法。它是由 Schnorr 演算法發展而來,在 RFC8032 中被定義實現。

package com.wdbyte;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Base64;

public class JEP339 {

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
        KeyPair kp = kpg.generateKeyPair();
        byte[] msg = "www.wdbyte.com".getBytes(StandardCharsets.UTF_8);
        Signature sig = Signature.getInstance("Ed25519");
        sig.initSign(kp.getPrivate());
        sig.update(msg);
        byte[] s = sig.sign();
        System.out.println(Base64.getEncoder().encodeToString(s));
    }
}

輸出結果:

VXlpxapU+LSWjVQ0QNJvdpUh6VI6PjSwOQ2pHu65bCfnLR13OyWKunlc9rc+7SMxCh2Mnqf7TmC/iOG8oimbAw==

2. JEP 360:Sealed Classes(密封類)預覽

我們都知道,在 Java 中如果想讓一個類不能被繼承和修改,這時我們應該使用 final 關鍵字對類進行修飾。不過這種要麼可以繼承,要麼不能繼承的機制不夠靈活,有些時候我們可能想讓某個類可以被某些型別繼承,但是又不能隨意繼承,是做不到的。Java 15 嘗試解決這個問題,引入了 sealed 類,被 sealed 修飾的類可以指定子類。這樣這個類就只能被指定的類繼承。

而且 sealed 修飾的類的機制具有傳遞性,它的子類必須使用指定的關鍵字進行修飾,且只能是 final sealed non-sealed 三者之一。

示例:犬類(Dog)只能被牧羊犬(Collie)和田園犬(TuGou)繼承,使用 sealed 關鍵字。

package com.wdbyte;

public  sealed interface Dog permits Collie, TuGou {
    //...
}

牧羊犬(Collie)只能被邊境牧羊犬(BorderCollie)繼承。

package com.wdbyte;

/**
 * 牧羊犬
 * @author www.wdbyte.com
 */
public sealed class Collie implements Dog permits BorderCollie {

}

邊境牧羊犬(BorderCollie)不能被繼承,使用 final 關鍵字。

package com.wdbyte;

/**
 *
 * @author www.wdbyte.com
 */
public final class BorderCollie extends Collie{
}

田園犬(ToGou)可以被任意繼承,使用 non-sealed 關鍵字。

package com.wdbyte;

/**
 * @author niulang
 */
public non-sealed class TuGou implements Dog {
}

3. JEP 371:Hidden Classes(隱藏類)

這個特性讓開發者可以引入一個無法被其他地方發現使用,且類的生命週期有限的類。這對執行時動態生成類的使用方式十分有利,可以減少記憶體佔用,下面是一個使用示例。

package com.wdbyte;

public class JEP371Test {
    public static String lookup() {
      return "www.wdbyte.com";
    }
}

把類 JEP371Test 編譯後的 Class 轉換成 Base64,然後使用 Java 15 新特性載入呼叫類中的 lookup 方法。

package com.wdbyte;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Base64;

/**
 * @author www.wdbyte.com
 */
public class JEP371 {

    private static String CLASS_INFO = "yv66vgAAADQAFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAOd3d3LndkYnl0ZS5jb20HAAoBABVjb20vd2RieXRlL0pFUDM3MVRlc3QBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAF0xjb20vd2RieXRlL0pFUDM3MVRlc3Q7AQAGbG9va3VwAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAPSkVQMzcxVGVzdC5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAEAAEAEgAAAAIAEw==";

    public static void main(String[] args) throws Throwable {
        byte[] classInBytes = Base64.getDecoder().decode(CLASS_INFO);
        Class<?> proxy = MethodHandles.lookup()
            .defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
            .lookupClass();

        System.out.println(proxy.getName());
        MethodHandle mh = MethodHandles.lookup().findStatic(proxy, "lookup", MethodType.methodType(String.class));
        String result = (String) mh.invokeExact();
        System.out.println(result);
    }
}

輸出結果:

com.wdbyte.JEP371Test/0x0000000800c01800
www.wdbyte.com

4. JEP 372:移除 Nashorn JavaScript 引擎

Nashorn JavaScript 引擎在 Java 8 中被引入,在 Java 11 中被標記為廢棄。由於 ECMAScript 語言發展很快,維護 Nashorn JavaScript 的成本過於高昂,在 Java 15 中被徹底刪除。

擴充套件閱讀:Nashorn JavaScript EngineDeprecate the Nashorn JavaScript Engine

5. JEP 373:重新實現 DatagramSocket API

Java 13 中重新實現了舊的 Socket API,在介紹 Java 13 時還有一部分做了這方面的介紹。

現在,Java 15 重新實現了遺留的 DatagramSocket

擴充套件閱讀:Java 13 新功能介紹

6. JEP 374:禁用和廢棄偏向鎖(Biased Locking)

在之前,JVM 在處理同步操作,如使用 synchronized 同步時,有一套鎖的升級機制,其中有一個鎖機制就是偏向鎖。然而通過目前的 Java 開發環境來看,使用這些被 synchronized 同步的類的機會並不多,如開發者更喜歡使用 HashMap 或者 ArrayList 而非 HashTableVector

即使換個角度,當初使用偏向鎖是為了提高效能,如今看來效能提升的程度和使用次數都不太有用。而偏向鎖的引入增加了 JVM 的複雜性。

所以現在偏向鎖被預設禁用,在不久的將來將會徹底刪除,對於 Java 15,我們仍然可以使用-XX:+UseBiasedLocking 啟用偏向鎖定,但它會提示 這是一個已棄用的 API。

7. JEP 375:instanceof 型別匹配 (二次預覽)

instanceof 型別匹配在 Java 14 中已經改進,這次僅僅再次預覽,沒有任何改動,用於接受更多的使用反饋。這個特性在 Java 16 中成為正式特性。

在之前,使用 instanceof 進行型別判斷之後,需要進行物件型別轉換後才能使用。

package com.wdbyte;

import java.util.ArrayList;
import java.util.List;

public class Java14BeaforInstanceof {

    public static void main(String[] args) {
        Object obj = new ArrayList<>();
        if (obj instanceof ArrayList) {
            ArrayList list = (ArrayList)obj;
            list.add("www.wdbyte.com");
        }
        System.out.println(obj);
    }
}

而在 Java 14 中,可以在判斷型別時指定變數名稱進行型別轉換,方便了使用。

package com.wdbyte;

import java.util.ArrayList;

public class Java14Instanceof {
    public static void main(String[] args) {
        Object obj = new ArrayList<>();
        if (obj instanceof ArrayList list) {
            list.add("www.wdbyte.com");
        }
        System.out.println(obj);
    }
}

可以看到,在使用 instanceof 判斷型別成立後,會自動強制轉換型別為指定型別。

輸出結果:

[www.wdbyte.com]

擴充套件閱讀:Java 14 新功能介紹

8. JEP 377:ZGC: 可擴充套件低延遲垃圾收集器(正式釋出)

ZGC 垃圾收集器在 Java 11 中被引入,但是因為收集器的複雜性,當初決定逐漸引入。然後不斷的聽取使用者的反饋建議修復問題。而現在,已經很久沒有收到使用者的問題反饋了,ZGC 是時候投入正式使用階段了。所以在 Java 15 中 ZGC 正式釋出,可以使用下面的引數啟用 ZGC。

$ java -XX:+UseZGC className

9. JEP 378: 文字塊

文字塊在 Java 12 JEP 326 原始字串文字 中引入,在 Java 13 JEP 355:文字塊(預覽) 中開始預覽,在 Java 14 JEP 368:文字塊(第二次預覽),而現在,在 Java 15 ,文字塊是正式的功能特性了。

String content = """
        {
            "upperSummary": null,\
            "sensitiveTypeList": null,
            "gmtModified": "2011-08-05\s10:50:09",
        }
         """;
System.out.println(content);

擴充套件閱讀:Java 14 新功能介紹- JEP368 文字塊

10. JEP 379:Shenandoah: 低停頓時間的垃圾收集器

Shenandoah 垃圾收集器在 Java 12 中開始引入,Java 15 中成為了正式功能的一部分,可以使用下面的引數啟用 Shenandoah 垃圾收集器。

java -XX:+UseShenandoahGC

但是 openJDK 15 中預設是沒有 Shenandoah 收集器,想要使用此功能可以下載 AdoptOpenJDK

為什麼 openJDK 中沒有 Shenandoah 垃圾收集器?

Shenandoah 是一個高效能、低暫停時間的垃圾收集器,它是 Red Hat 主導的專案。當 Red Hat 第一次提議將 Shenandoah 貢獻給 OpenJDK 時,Oracle 明確表示不想支援它,OpenJDK 作為一個免費軟體,不想支援 Red Hat 的 Shenandoah 完全沒有問題。

最後 Red Hat 選擇和 Oracle 合作設計一個真正乾淨的可插拔垃圾收集器介面,允許任何人輕鬆選擇垃圾收集器以包含在他們的構建中。最終 Shenandoah 進入了 JDK 12,但是沒有構建進 OpenJDK。

11. JEP 384:Records(二次預覽)

在 Java 14 中引入了 Record 類,Java 15 中對 Record 進行了增強。使它可以支援密封型別、Record 註解以及相關的反射 API 等。

示例:Record 支援密封(sealed)型別。

package com.wdbyte;

/**
 * @author www.wdbyte.com
 */
public sealed interface DataBase permits DataBaseSelect, DataBaseUpdate {
}

final record DataBaseSelect(@Deprecated String table, String sql) implements DataBase {
}

final record DataBaseUpdate() implements DataBase {
}

java.lang.Class 增加了兩個公共方法用於獲取 Record 類資訊:

  1. RecordComponent[] getRecordComponents()

  2. boolean isRecord()

其他更新

JEP 381:刪除 Solaris 和 SPARC 埠

Java 14 JEP 362棄用了 Solaris/SPARC、Solaris/x64 和 Linux/SPARC 埠,現在它在 Java 15 中被正式刪除。

JEP 383:外部記憶體訪問 API(第二個孵化器)

JEP 385:廢棄 RMI 啟用機制

只是廢棄 RMI 啟用機制,不影響 RMI 其他功能。

參考

  1. https://openjdk.java.net/projects/jdk/15/
  2. https://docs.oracle.com/en/java/javase/14/docs/specs/rmi/activation.html
  3. https://mkyong.com/java/what-is-new-in-java-15/

系列文章

訂閱

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

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

文章持續更新,可以關注公眾號「 程式猿阿朗 」或訪問「未讀程式碼部落格 」。

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

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

等你好久

相關文章