jdk14 新特性

Java14新特性

1. instanceof 模式匹配

舊:類型匹配後的使用,需要強制轉換

private static void old(Object obj) {
    if(obj instanceof String){
        String str = (String)obj;
        System.out.println(str.contain("java"));
    }else{
        System.out.println("error");
    }
}

新:類型匹配過程中就可以完成轉換,並且定義變量str

private static void New(Object obj) {
    if(obj instanceof String str){
        System.out.println("無需強制轉換");
    }else{
        System.out.println("error");
    }
}

注意:str變量只能在它所在if中使用

private static void New(Object obj) {
    if(obj instanceof String str){
        System.out.println("無需強制轉換");
    }else{
        System.out.println(str.contains("java"));
        System.out.println("error");
    }
}

這樣寫是錯誤的。

2. 實用的NullPointerException

該特性改進了空指針異常的可讀性,能更準確地給出null變量的信息。

回顧Java8,提供了Optional來處理空指針異常。

舉例:

class Bank{
    private Customer customer;

    public Bank(Customer customer) {
        this.customer = customer;
    }
    public Bank(){}
    public Customer getCustomer(){
        return customer;
    }
    public void setCustomer(Customer customer){
        this.customer = customer;
    }
}

class Customer{
    private Account account;

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public Customer(Account account) {
        this.account = account;
    }
    public Customer() {
    }

}

class Account{
    private int balance;

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

    public Account(int balance) {
        this.balance = balance;
    }
}

main方法:

public class Test02 {
    public static void main(String[] args) {
        Bank bank = new Bank(new Customer());
        bank.getCustomer().getAccount().getBalance();
    }
}

很明顯我們沒有實例化 Account對象,這個代碼bank.getCustomer().getAccount()運行會報空指針

運行看看結果:

Exception in thread "main" java.lang.NullPointerException
	at NullPointerException.Test02.main(Test02.java:6)

的確有報錯,但是沒有給出具體哪兒報錯了。

接下來我們在VM options加個指令:-XX:+ShowCodeDetailsInExceptionMessages

再運行看看結果:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "NullPointerException.Account.getBalance()" because the return value of "NullPointerException.Customer.getAccount()" is null
	at NullPointerException.Test02.main(Test02.java:6)

這樣就顯示出詳細報錯信息了。

3. Record(預覽特性)

Java語言架構師Brian Goetz吐槽Java語言太囉嗦,有太多重複的,容易出錯的代碼,如構造函數、getter/setter等。

Java14 也許最令人興奮的,同時也是最令人驚訝的創新就是:Record類型的引入!

使用record來減少類聲明語法,效果類似lombok的的@Data註解。

它們的個共同的是類的部分或全部狀態可以直接在類頭中描述。

和枚舉類一樣,記錄也是類的一種受限形式。

舉例

原來定義一個實體類

public final class User {
    private final String name;
    private final User partner;

    public User(String name, User partner) {
        this.name = name;
        this.partner = partner;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;
        User user = (User) o;
        return name.equals(user.name) &&
                partner.equals(user.partner);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, partner);
    }

    public String getName() {
        return name;
    }

    public User getPartner() {
        return partner;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", partner=" + partner +
                '}';
    }
}

需要這麼多代碼,雖然IDE可以自動生成,但是我們瀏覽的時候就顯得很複雜。

Java14提供了一種Record創建類的方式

在這裏插入圖片描述

現在只需要這樣創建:

public record Person(String name,Person partner) {
	//成員變量定義在頭部
}

測試

public static void main(String[] args) {
    //測試構造器
    Person p1 = new Person("Romio",new Person("Julia",null));
    System.out.println(p1);
}

##輸出
Person[name=Romio, partner=Person[name=Julia, partner=null]]
相當於record提供了toString方法

我們查看一下Person的字節碼文件:

public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final Record.Person partner;

    public Person(java.lang.String name, Record.Person partner) { /* compiled code */ }

    public java.lang.String toString() { /* compiled code */ }

    public final int hashCode() { /* compiled code */ }

    public final boolean equals(java.lang.Object o) { /* compiled code */ }

    public java.lang.String name() { /* compiled code */ } //相當於getName()方法

    public Record.Person partner() { /* compiled code */ } //相當於getPartner()方法
}

注意事項:

  • 我們還可以在Record聲明的類中定義靜態字段、靜態方法、構造器或實例方法

  • 不能在Record聲明的類中定義非靜態實例字段;類不能聲明爲abstract;不能聲明顯式的父類等。

public record Person(String name,Person partner) {

    //靜態屬性
    public static String nation;

    //靜態方法
    public static String showNation(){
        return nation;
    }
    //構造器
    public Person(String name){
        this(name,null);
    }
    //實例方法
    public String getNameToUpperCase(){
        return name.toUpperCase();
    }

}
  • 因爲record聲明默認爲final類,類不能被繼承,類成員變量不可被更改(即set方法)

不合法:

abstract record A{  //不可用abstract修飾
    
}
record B() extends Thread{ //不可繼承其他類,因爲record隱式繼承了Record父類,由於Java的單繼承,不可再顯示繼承其他父類。
}

值得一提:Java.lang.Class對象中添加了兩個新方法:

RecordComponent[] getRecordComponents()
boolean isRecord()

用於反射的使用

4. switch表達式的使用

jdk12、13的預覽版如今已成爲正式版

switch可以當做語句使用,也可以當作表達式使用。

具體情況:使用->來替代以前的: break;另外還提供了yield來在block中返回值。

最早的switch

public class Test04 {
    public static void main(String[] args) {
        Week day = Week.FRIDAY;
        switch (day){
            case MONDAY:
            case TUESDAY:
            case WEDNESDAY:
                System.out.println(3);
                break;
            case THUSDAY:
                System.out.println(4);
                break;
            case FRIDAY:
                System.out.println(5);
                break;
            case SATURDAY:
                System.out.println(6);
                break;
            case SUNDAY:
                System.out.println(7);
                break;
            default:
                break;
        }
    }
}

enum Week{
    SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THUSDAY,FRIDAY,SATURDAY;
}

JDK12的新特性:引用switch表達式

public static void siwtch12(){
    switch (day) {
        case MONDAY, TUESDAY, WEDNESDAY -> System.out.println(3);
        case THUSDAY -> System.out.println(4);
        case FRIDAY -> System.out.println(5);
        case SATURDAY -> System.out.println(6);
        case SUNDAY -> System.out.println(7);
        default -> System.out.println(1);
    }
}

//還可以用一個參數接收
public static void siwtch12(){
    Week day = Week.FRIDAY;
    int num = switch (day) {
        case MONDAY, TUESDAY, WEDNESDAY -> 3;
        case THUSDAY -> 4;
        case FRIDAY -> 5;
        case SATURDAY -> 6;
        case SUNDAY -> 7;
        default -> 1;
    };

    System.out.println(num);

}

JDK13新特性:引入yield關鍵字,用於返回指定的數據,結束switch結構,可以理解爲return

public void siwtch13(){
        String x = "5";
        int num = switch (x){
            case "1"->1;
            case "2"->2;
            case "3":yield 3;
            default -> {
                System.out.println("default..");
                yield 4;
            }
        };
        System.out.println(num);
    }

5. 文本塊(預覽版)

jdk14增加了兩個轉義字符:\禁止換行 \s空格

目標:

  • 簡化跨越多行的字符串,避免對換行等特殊子進行轉義,簡化編寫Java程序
  • 增強Java程序中用字符串表示的其他語言的代碼的可讀性
  • 解析新的轉義序列
//jdk13以前
String text1 = "China's football club Guangzhou Evergrande " +
    "and Taobao reported a loss of 1.9 billion yuan (274 million US dollars)" +
    " in 2019, according to the National Equities Exchange " +
    "and Quotations (NEEQ) listed company's annual report " +
    "released on Wednesday.";

System.out.println(text1);

//jdk13新特性(前後3個雙引號包裹文本)
String text2 = """
    China's football club Guangzhou Evergrande 
    and Taobao reported a loss of 1.9 billion yuan (274 million US dollars) 
    in 2019, according to the National Equities Exchange
    and Quotations (NEEQ) listed company's annual report
    released on Wednesday.
    """;
//html
@Test
public void HtmlTest(){
    String html1 = "<!DOCTYPE html>\n" +
        "<html lang=\"en\">\n" +
        "<head>\n" +
        "  <meta charset=\"UTF-8\">\n" +
        "  <title>Title</title>\n" +
        "</head>\n" +
        "<body>\n" +
        "hello \n" +
        "</body>\n" +
        "</html>";

    String html2 = """
        <!DOCTYPE html>
        <html lang="en">
        <head>
        <meta charset="UTF-8">
        <title>Title</title>
        </head>
        <body>
        hello\s
        </body>
        </html>
        """;
}

還有一些如JSON、SQL語句都可以這樣使用。

JDK14的新特性,\\s

@Test
public void TestJDK14(){
    String html2 = """
        <!DOCTYPE html>\
        <html lang="en">
        <head>
        <meta charset="UTF-8">
        <title>Title</title>
        </head>
        <body>
        hello\sworld
        </body>
        </html>
        """;
        
    System.out.println(html2);
}

//結果
<!DOCTYPE html><html lang="en">  //沒有換行
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
hello world  //中間多了空格
</body>
</html>


Process finished with exit code 0

6. 棄用一個垃圾收集器組合

在這裏插入圖片描述

jdk9廢除(Serial+CMS) (ParNew+Serial Old)

jdk14棄用(ParallelScavenge +SerialOld GC)

棄用-XX:+UseParallelGC-XX :- UseParallelOldGC組合,-XX:UseParallelOld GC選項也被棄用,因爲它的作用是取消老年代並行GC,支持老年代串行GC。因此,任何與UseUseParallelOldGC選項有關的用法都會輸出警告。

7. 刪除CMS垃圾回收器

自從G1(基於Region分代)橫空出世後,CMS在JDK9就被標記爲棄用。

原因:

  • 會產生內存碎片,導致併發清除後,用戶線程可用的空間不足
  • 既然強調了併發,CMS收集器對CPU資源非常敏感
  • CMS收集器無法處理浮動垃圾(一個線程清理垃圾,另一個線程產生垃圾)。

兩個新的收集器

ZGC(JDK11出現) 和 Shenandoah (open jdk12)

特點:低停頓時間/低延遲

8. ZGC (試驗狀態)

在儘可能對系統吞吐量影響不大的前提下,實現在任意堆內存大小下都可以把垃圾收集的停頓時間限制在10ms以內的低延遲。

它是一款以低延遲爲首要目標的一款垃圾收集器

ps: 還有一些不太常用的新特性,這邊就不指出了!

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