JDK11


1 JDK11新特性介紹

1.1 初識JDK11新特性

  • 北京時間2018年9月26日,Oracle官方宣布JDK11(18.9LTS)正式發布。這是Java8以后支持的首個長期版本,非常值得關注。最近發布的JDK11將帶來ZGC、HttpClient等重要特性,一共包含了17個JEP(Java Enhancement Proposals,Java增強提案)。
  • 本次發布的JDK11和2017年9月份發布的JDK9以及2018年發布的JDK11相比,最大的區別就是:在長期支持方面,Oracle表示會對JDK11提供大力支持。

1.2 JDK11新特性更新列表

  • 我們可以在如下網站中查看JDK11的新特性增強提案詳情:
http://openjdk.java.net/projects/jdk/11/

JDK11新特性特性列表

2 JDK11新特性詳解

2.1 基於嵌套的訪問控制

  • 如果在一個類中嵌套了多個類,各個類可以直接訪問彼此的私有成員。JDK11在private、public、protected的基礎上,JVM又提供了新的訪問機制:Nest。

  • JDK11之前的如下案例:

package com.sunxiaping;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 10:33
 */
public class Outer {
    private String str ;

    public class Inner{
        public void method(){
            System.out.println("str = " + str);
        }
    }
}
  • 在JDK11之前,執行編譯的最終結果的class文件形式如下:
public class Outer {
  private String str;
  public String access$000(){
      return str;
  }  
}

public class Inner$Outer {
  public void method() {
    System.out.println("str = " + Outer.access$000(Outer.this));
  }
}
  • 以上方案雖然從邏輯上講,內部類和外部類相同代碼實體的一部分,但它被編譯為一個單獨的類,因此,它需要編譯器創建合成橋接方法,以提供對外部類的私有字段的訪問。
  • 這種方案一個很大的坑是反射的時候有問題,當使用反射在內部類中訪問外部類私有成員str時會報IllegalAccessException異常,這個是讓人難以理解的,因為反射還是源碼級訪問的權限。
package com.sunxiaping;

import java.lang.reflect.Field;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 10:33
 */
public class Outer {
    private String outInt;

    public class Inner {
        public void method() {
            try {
                Class outerClass = Outer.class;
                Outer outer = Outer.class.getDeclaredConstructor().newInstance();
                Field field = outerClass.getDeclaredField("outInt");
                field.set(outer, "100");

                System.out.println("str = " + outer.outInt);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
package com.sunxiaping;

/**
 * 基於嵌套的訪問控制
 *
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 09:06
 */
public class Demo {
    public static void main(String[] args) {
        new Outer().new Inner().method();
    }
}
  • JDK11開始,嵌套時一種訪問控制上下文,它運行多個class同屬一個邏輯代碼塊,但是被編譯成多個分散的class文件,它們訪問彼此的私有成員無需通過編譯器添加訪問擴展犯法,而是可以直接訪問,如果上述代碼可以直接通過反射訪問外部類的私有成員,而不會出現權限問題。

2.2 Lambda參數局部變量

  • 在聲明隱式類型的Lambda表示式形參的時候允許使用var,這樣使用的好處在於使用Lambda表示式時可以給參數加上注解。

  • 示例:

package com.sunxiaping;

import java.util.List;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 11:27
 */
public class LambdaDemo {
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8);
        list.stream().sorted((@Deprecated var a,@Deprecated var b) -> a - b).forEach(System.out::println);
    }
}

2.3 String新增處理方法

  • 判斷字符串是否為空白:
//如果字符串都為空格,制表符、tab的情況,返回true,否則返回false 
public boolean isBlank();
  • 判斷字符串是否為空:
//判斷字符串內容是否為空,不忽略空格等
public boolean isEmpty()
  • 去除首尾空白:
//可以去除全角的空白字符
public String strip()
  • 去除首尾空白:
//不能去除全角的空白字符
public String trim()
  • 去除尾部空白:
public String stripTrailing()
  • 去除首部空白:
public String stripLeading()
  • 復制字符串:
public String repeat(int count) 
  • 行數統計:
public Stream<String> lines()
  • 示例:判斷字符串是否為空白和判斷字符串是否為空
package com.sunxiaping;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 13:25
 */
public class StringDemo {
    public static void main(String[] args) {
        String str = "";
        System.out.println(str.isBlank()); //true
        System.out.println(str.isEmpty()); //true

        str = "  ";
        System.out.println(str.isBlank()); //true
        System.out.println(str.isEmpty()); //false


        str = "abc";
        System.out.println(str.isBlank()); //false
        System.out.println(str.isEmpty()); //false

    }
}
  • 示例:去除首尾空白
package com.sunxiaping;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 13:25
 */
public class StringDemo {
    public static void main(String[] args) {
        String str = " 哈哈 ";

        System.out.println(str.strip());
        System.out.println(str.trim());

    }
}
  • 示例:去除首部空白和尾部空白
package com.sunxiaping;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 13:25
 */
public class StringDemo {
    public static void main(String[] args) {
        String str = " 哈哈 ";

        System.out.println(str.stripTrailing()); //去除尾部空白
        System.out.println(str.stripLeading()); //去除首部空白

    }
}
  • 示例:復制字符串
package com.sunxiaping;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 13:25
 */
public class StringDemo {
    public static void main(String[] args) {
        String str = "我是中國人,我愛中國。";
        //復制字符串
        System.out.println(str.repeat(3)); //我是中國人,我愛中國。我是中國人,我愛中國。我是中國人,我愛中國。

    }
}
  • 示例:行數統計
package com.sunxiaping;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 13:25
 */
public class StringDemo {
    public static void main(String[] args) {
        String str = "我\n是\n中\n國\n人\n,我\n愛\n中\n國。";
        System.out.println(str.lines().count()); //行數統計:9
    }
}

2.4 集合新增的API

  • 集合轉換數組支持方法引用。
default <T> T[] toArray(IntFunction<T[]> generator)
  • 示例:
package com.sunxiaping;

import java.util.Arrays;
import java.util.List;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 13:51
 */
public class ListDemo {
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5);

        //JDK11之前轉換數組
        Integer[] array = list.toArray(new Integer[0]);

        Arrays.stream(array).forEach(System.out::println);


        //JDK11轉換數組
        Integer[] array1 = list.toArray(Integer[]::new);

        Arrays.stream(array1).forEach(System.out::println);
    }
}

2.5 更方便的操作IO

  • Path類獲取指定目錄的路徑:
//等同於Paths.get()方法
public static Path of(String first, String... more)
  • Files更方便的讀寫數據:
//寫數據
public static Path writeString(Path path, CharSequence csq, OpenOption... options)
//讀取數據
public static String readString(Path path, Charset cs) throws IOException
  • 示例:
package com.sunxiaping;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 14:04
 */
public class IODemo {
    public static void main(String[] args) throws Exception {
        //Files類更方便的讀寫數據方法
        Files.writeString(Path.of("demo.txt"),"在學習Java11");
        String str = Files.readString(Path.of("demo.txt"), StandardCharsets.UTF_8);
        System.out.println(str);
    }
}

2.6 HttpClient

2.6.1 概述

  • 從Java9開始開始引入了一個處理HTTP請求的Http Client API,不過當時一直處於孵化階段,而在Java11中已經成為正式可用狀態,作為一個標准API提供在java.net.http供我們使用,該API支持同步和異步請求。

  • HttpClient目的是取代JDK8中的httpURLConnection。

2.6.2 優勢

  • API是易於使用的,包括簡單的阻塞模式。
  • 支持通知機制如HTTP消息頭收到、錯誤碼、HTTP消息體收到。
  • 簡潔的API能夠支持80~90%的需求。
  • 支持標准和通用身份驗證機制。
  • 能夠輕松使用WebSocket。
  • 支持HTTP2。
  • 執行和現有網絡API一致的安全檢查。
  • 對Lambda表達式等新語言功能友好。
  • 對嵌入式系統友好,避免永久運行的后台線程。
  • 支持HTTPs/TLS。
  • 滿足HTTP1.1和HTTP2的性能要求。

2.6.3 應用示例

  • 示例:
package com.sunxiaping;

import org.junit.Test;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 14:31
 */
public class HttpClientDemo {

    /**
     * 同步
     */
    @Test
    public void test() throws IOException, InterruptedException {
        //創建HttpClient對象
        HttpClient httpClient = HttpClient.newHttpClient();
        //創建HttpRequest請求對象
        HttpRequest httpRequest = HttpRequest.newBuilder(URI.create("https://www.baidu.com")).GET().build();
        //使用HttpClient對象發起request請求,得到請求響應對象response
        HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
        //響應狀態碼
        System.out.println("響應狀態碼:" + response.statusCode());
        //響應信息
        System.out.println("響應信息:" + response.body());
    }

    /**
     * 異步
     */
    @Test
    public void test2() {
        //創建HttpClient對象
        HttpClient httpClient = HttpClient.newHttpClient();
        //創建HttpRequest請求對象
        HttpRequest httpRequest = HttpRequest.newBuilder(URI.create("https://www.baidu.com")).GET().build();
        //發送請求
        CompletableFuture<HttpResponse<String>> future = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString());
        //異步監聽結果數據
        future.whenComplete((response, throwable) -> {
            //結果數據的處理
            if (null != throwable) {
                throwable.printStackTrace();
            } else {
                //響應狀態碼
                System.out.println("響應狀態碼:" + response.statusCode());
                //響應信息
                System.out.println("響應信息:" + response.body());
            }
        }).join(); //阻塞等待異步結果

        System.out.println("結束程序");

    }
}

2.7 改進Aarch64內在函數

  • 改進現有的字符串和數組函數,並在Aarch64處理器上為java.lang.Math下的sin、cos和log函數實現新的內聯函數,從而實現專用的CPU架構下提高應用程序的性能。

  • 示例:

package com.sunxiaping;

import java.util.concurrent.TimeUnit;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 14:54
 */
public class Aarch64Demo {
    public static void main(String[] args) {
        long startTime = System.nanoTime();
        for (int i = 0; i < 10000000; i++) {
            Math.sin(1);
            Math.cos(1);
            Math.log(1);
        }
        long endTime = System.nanoTime();

        System.out.println(TimeUnit.NANOSECONDS.toMillis(endTime - startTime));
    }
}

2.8 增強java啟動器支持運行單個java源程序文件的程序

  • 使用java命令可以編譯和運行源文件程序。

  • 示例:

package com.sunxiaping;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 15:59
 */
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
java HelloWorld.java

使用java命令可以編譯和運行源文件程序

2.9 Epsilon垃圾收集器

2.9.1 概述

  • Epsilon垃圾收集器,又稱為無操作垃圾收集器。
  • JDK對這個特性的描述是:開發一個處理內存分配但是不實現任何實際內存回收機制的GC,一旦Java的堆內存被耗盡,JVM就直接關閉。
  • 如果有system.gc();調用,實際上什么也不會發生垃圾對象的回收操作,因為沒有內存回收,這個實現可能會警告用戶嘗試強制GC是徒勞的。

2.9.2 應用示例

  • 示例:使用G1垃圾收集器
package com.sunxiaping;

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 16:19
 */
public class Garbage {
    private int number;

    public Garbage() {
    }

    public Garbage(int number) {
        this.number = number;
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println(number);
    }
}
package com.sunxiaping;

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

/**
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-03 16:19
 */
public class G1Demo {
    public static void main(String[] args) {
        System.out.println("程序開始");
        List<Garbage> list = new ArrayList<>();
        long count = 0;
        while (true) {
            list.add(new Garbage(list.size() + 1));

            if (list.size() == 1000000 && count == 0) {
                list.clear();
                count++;
            }
        }
    }
}
  • 啟動參數設置:
-Xms100m -Xmx100m

使用Epsilon垃圾收集器前

會發現G1一直回收對象,直到內存不夠用。

  • 使用Epsilon垃圾收集器,需要設置啟動參數:
-XX:+UnlockExperimentalVMOptions
-XX:+UseEpsilonGC
-Xms100m
-Xmx100m

使用Epsilon垃圾收集器后

會發現很快就內存溢出了,因為Epsilon不會去回收對象。

2.9.3 應用場景

  • 性能測試:Epsilon垃圾收集器可以幫助我們過濾掉GC引起的性能假象。
  • 內存壓力測試:在測試Java代碼的時候,確定分配內存的閾值有助於設置內存壓力常量值。
  • 非常短的JOB任務:對象這種任務,接受GC清理堆就是浪費空間。
  • VM接口測試:以VM開發視角,有一個簡單的GC實現,有助於理解VM-GC的最小接口實現,它也用於證明VM-GC接口的健壯性。
  • ……

2.10 ZGC可伸縮低延遲垃圾收集器

2.10.1 ZGC的目標

  • GC是Java主要優勢之一。然而,當GC停頓太長,就會開始影響應用的響應時間。消除或者減少GC停頓時長,Java將對更廣泛的應用場景是一個更有吸引力的平台。此外,現代系統中可用內存不斷增長,用戶和程序員希望JVM能夠以高效的方式充分的利用這些內存,並且無需長時間的GC暫停時間。
  • 今天,應用程序同時為數千甚至數百萬用戶提供服務的情況並不多見。這些應用程序需要大量內存,但是,管理所欲內存可能會輕易影響應用程序性能。為了解決這個問題,Java11引入了ZGC垃圾收集器作為實驗性垃圾收集器的實現。
  • ZGC全稱Z Garbage Collector,是一款可伸縮的低延遲、高並發的垃圾回收器,旨在實現以下目標:
  • 1️⃣停頓時間不超過10ms。
  • 2️⃣停頓時間不隨heap大小或存活對象大小增大而增大。
  • 3️⃣可以處理從幾百G到幾TB的內存大小,遠遠超過前一代的G1。
  • 4️⃣初識只支持64位系統。

2.10.2 用法

  • 運行我們的應用程序時,我可以使用以下命令選項啟動ZGC:
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
  • 需要注意的是,ZGC處於實驗階段。

2.10.3 平台支持

  • ZGC目前只在Linux/x64上可用,如果有足夠的需求,將來可能會增加對其他平台的支持。


免責聲明!

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



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