java9新特性(簡述十大新特性)

java 9 提供了超過 150 項新功能特性,包括備受期待的模塊化系統、可交互的 REPL 工具:jshell,JDK 編譯工具,Java 公共 API 和私有代碼,以及安全增強、擴展提升、性能管理改善等。可以說 Java 9 是一個龐大的系統工程,完全做了一個整體改變。但本博文只介紹最重要的十大新特性

特性列表

  • 平臺級modularity(原名:Jigsaw) 模塊化系統
  • Java 的 REPL 工具: jShell 命令
  • 多版本兼容 jar 包(這個在處理向下兼容方面,非常好用)
  • 語法改進:接口的私有方法
  • 語法改進:UnderScore(下劃線)使用的限制
  • 底層結構:String 存儲結構變更(這個很重要)
  • 集合工廠方法:快速創建只讀集合
  • 增強的 Stream API
  • 全新的 HTTP 客戶端 API
  • 其它特性

它的新特性來自於100於項JEP和40於項JSR

1. 平臺級modularity(原名:Jigsaw) 模塊化系統

模塊化系統Java7開始籌備,Java8進行了大量工作,Java9才落地。首先帶來最直觀的感受,就是目錄結構的感受:
JDK8以及以前版本:

                                              

而Java9的結構目錄: 

                                          

對目錄做相應的介紹: 

     

Java 9 的定義功能是一套全新的模塊系統。當代碼庫越來越大,創建複雜,盤根錯節的“意大利麪條式代碼”的機率呈指數級的增長。這時候就得面對兩個基礎的問題: 很難真正地對代碼進行封裝, 而系統並沒有對不同部分(也就是 JAR 文件)之間的依賴關係有個明確的概念。每一個公共類都可以被類路徑之下任何其它的公共類所訪問到, 這樣就會導致無意中使用了並不想被公開訪問的 API。此外,類路徑本身也存在問題: 你怎麼知曉所有需要的 JAR 都已經有了, 或者是不是會有重複的項呢? 模塊系統把這倆個問題都給解決了

在模塊的 src 下創建 module-info.java 文件,來描述依賴和導出(暴露)。

requires:指明對其它模塊的依賴。
exports:控制着哪些包可以被其它模塊訪問到。所有不被導出的包
默認都被封裝在模塊裏面。

2、Java 的 REPL 工具: jShell 命令

REPL:read - evaluate - print - loop
這個簡單的說就是能想腳本語言那樣,所見即所得。之前我們用java,哪怕只想輸出一句hello world,都是非常麻煩的。需要建文件、寫代碼、編譯、運行等等。現在有了jShell工具,實在太方便了

  • 即寫即得、快速運行


這樣我就進入了jshell環境。下面Hello World就是這麼簡單了

  • jShell 也可以從文件中加載語句或者將語句保存到文件中(使用Open命令)
  • jShell 也可以是 tab 鍵進行自動補全和自動添加分號

    列出當前 session 裏所有有效的代碼片段:/list

3、多版本兼容 jar 包(這個在處理向下兼容方面,非常好用)

當一個新版本的 Java 出現的時候,你的庫用戶要花費數年時間纔會
切換到這個新的版本。這就意味着庫得去向後兼容你想要支持的最老
的 Java 版本(許多情況下就是 Java 6 或者 Java7)。這實際上意味着
未來的很長一段時間,你都不能在庫中運用 Java 9 所提供的新特性。
幸運的是,多版本兼容 jar 功能能讓你創建僅在特定版本的 Java 環境
中運行庫程序選擇使用的 class 版本

案例:略

4、語法改進:接口的私有方法

在 Java 9 中,接口更加的靈活和強大,連方法的訪問權限修飾符
都可以聲明爲 private 的了,此時方法將不會成爲你對外暴露的 API
的一部分(個人認爲,這肯定是JDK8遺漏了的一個點,哈哈)
看個例子:

 public static String staticFun() {
        privateFun();
        return "";
    }

    default String defaultFun() {
        privateFun();
        return "";
    }

    private static void privateFun() {
        System.out.println("我是私有方法~");
    }

這樣子是沒有問題,可以正常調用和使用的。但是需要注意一下兩點

  1. 私有方法可以是static,也可以不是。看你需要default方法調用還是static方法調用
  2. 私有方法只能用private修飾,不能用protected。若不寫,默認就是public,就是普通靜態方法了。
default String defaultFun() {
        privateFun();
        return "";
    }

    private void privateFun() {
        System.out.println("我是私有方法~");
    }

4、語法改進:鑽石操作符(Diamond Operator)使用升級 泛型

在 java 8 中如下的操作是會報錯的:

 public static void main(String[] args) {
        Set<String> set1 = new HashSet<>(); //最常用的初始化
        //Set<String> set2 = new HashSet<>(){}; //在JDK8中報錯
        Set<String> set2 = new HashSet<String>(){}; //這樣在JDK8中也正常
        Set<String> set3 = new HashSet<String>(){{}}; //這樣也都是正常的
    }

由此課件,報錯的那種情況是因爲在JDK8中,還不能直接推斷出鑽石操作符裏面的類型而報錯。而我們在JDK9以後,就可以直接這麼寫了:

public static void main(String[] args) {
        Set<String> set1 = new HashSet<>(); //最常用的初始化
        Set<String> set2 = new HashSet<>(){}; //在JDK8中報錯
        Set<String> set3 = new HashSet<>(){{}}; //這樣也都是正常的
    }

這樣寫都是不會報錯,可以直接書寫使用的。相當於直接創建了一個HashMap的子類。

5、語法改進:UnderScore(下劃線)使用的限制

這個點非常的小。距離說明就懂了
在Java8中,我們給變量取名直接就是_

public static void main(String[] args) {
       String _ = "hello";
       System.out.println(_); //hello
    }

這裏寫圖片描述
我們很清晰的看到,Java8其實給出了提示,但是編譯運行都是能通過的,而到了Java9:
這裏寫圖片描述
直接就提示_是關鍵字,編譯都過不了了。

6、底層結構:String 存儲結構變更(這個很重要)

UTF-8表示一個字符是個動態的過程,可以能用1、2、3個字節都是有可能的。但是UTF-16明確的就是不管你是拉丁文、中文等,都是恆定的用兩個字節表示

JDK8的字符串存儲在char類型的數組裏面,不難想象在絕大多數情況下,char類型只需要一個字節就能表示出來了,比如各種字母什麼的,兩個字節存儲勢必會浪費空間,JDK9的一個優化就在這,內存的優化。
Java8:

private final char value[];

Java9:

private final byte[] value;

結論:String 再也不用 char[] 來存儲啦,改成了 byte[] 加上編碼標
記,節約了不少空間。由於底層用了字節數組byte[]來存儲,所以遇上非拉丁文,JDK9配合了一個encodingFlag來配合編碼解碼的

so,相應的StringBuffer 和 StringBuilder 也對應的做出了對應的變化。

有的人擔心,這會不會影響到我的charAt方法呢?那我們來看看:

public static void main(String[] args) {
        String str = "hello";
        String china = "方世享";
        System.out.println(str.charAt(1)); //e
        System.out.println(china.charAt(1)); //世
    }

顯然,這個對上層的調用者是完全透明的,完全是底層的數據結構存儲而已。但是有必要對比一下源碼,還是有非常大的區別的:
java8的charAt方法源碼: 實現起來簡單很多吧

 public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }

java9的charAt方法源碼:

public char charAt(int index) {
        if (isLatin1()) {
            return StringLatin1.charAt(value, index);
        } else {
            return StringUTF16.charAt(value, index);
        }
    }

7、集合工廠方法:快速創建只讀集合

爲了保證數據的安全性,有時候我們需要創建一個只讀的List。在JDK8的時候,我們只能這麼做:

Collections.unmodifiableList(list)
Collections.unmodifiableSet(set)
Collections.unmodifiableMap(map)

Tips:Arrays.asList(1,2,3)創建的List也是隻讀的,不能添加刪除,但是一般我們並不會把他當作只讀來用。

可以說是比較繁瑣的一件事。Java 9 因此引入了方便的方法,這使得類似的事情更容易表達。**調用集合中靜態方法 of(),可以將不同數量的參數傳輸到此工廠方法。此功能可用於 Set 和 List,也可用於 Map 的類似形式。此時得到
的集合,是不可變的:**

List<String> list = List.of("a", "b", "c");
        Set<String> set = Set.of("a", "b", "c");
        //Map的兩種初始化方式,個人喜歡第二種,語意更加清晰些,也不容易錯
        Map<String, Integer> map1 = Map.of("Tom", 12, "Jerry", 21,
                "Lilei", 33, "HanMeimei", 18);
        Map<String, Integer> map2 = Map.ofEntries(
                Map.entry("Tom", 89),
                Map.entry("Jim", 78),
                Map.entry("Tim", 98)
        );

處於好奇心,可以讓大家再對比一下類型,看看怎麼實現的:

public static void main(String[] args) {
        List<String> list = List.of("a", "b", "c");
        List<String> listOld = Collections.unmodifiableList(Arrays.asList("a", "b", "c"));
        System.out.println(list.getClass().getName()); //java.util.ImmutableCollections$ListN
        System.out.println(listOld.getClass().getName()); //java.util.Collections$UnmodifiableRandomAccessList
    }

8、增強的 Stream API

在 Java 9 中,Stream API 變得更好,Stream 接口中添加了 4 個新的方法:dropWhile, takeWhile, ofNullable,還有個 iterate 方法的新重載方法,可以讓你提供一個 Predicate (判斷條件)來指定什麼時候結束迭代。

除了對 Stream 本身的擴展,Optional 和 Stream 之間的結合也
得到了改進。現在可以通過 Optional 的新方法 stream() 將一個
Optional 對象轉換爲一個(可能是空的) Stream 對象

  • takeWhile():返回從開頭開始的儘量多的元素
  • dropWhile() :行爲與 takeWhile 相反,返回剩餘的元素
  • ofNullable():Stream 不能全爲 null,否則會報空指針異常。而 Java 9 中的ofNullable健壯性就比of強很多。可以包含一個非空元素,也可以創建一個空 Stream
//報 NullPointerException   因爲Of方法不允許全爲null的
//Stream<Object> stream1 = Stream.of(null);
//System.out.println(stream1.count());


//ofNullable():允許值爲 null
Stream<Object> stream1 = Stream.ofNullable(null);
System.out.println(stream1.count());//0
  • iterator()重載方法。如下,相當於不僅僅是limit,而是可以寫邏輯來判斷終止與否了

    

9、全新的 HTTP 客戶端 API

HTTP,用於傳輸網頁的協議,早在 1997 年就被採用在目前的 1.1
版本中。直到 2015 年,HTTP2 才成爲標準。

Java 9 中有新的方式來處理 HTTP 調用。它提供了一個新的 HTTP客戶端( HttpClient ), 它 將 替代僅適用於 blocking 模式的HttpURLConnection (HttpURLConnection是在HTTP 1.0的時代創建的,並使用了協議無關的方法),並提供對 WebSocket 和 HTTP/2 的支持。

此外,HTTP 客戶端還提供 API 來處理 HTTP/2 的特性,比如流和
服務器推送等功能。全新的 HTTP 客戶端 API 可以從 jdk.incubator.httpclient 模塊中獲取。因爲在默認情況下,這個模塊是不能根據 classpath 獲取的,需要使用 add modules 命令選項配置這個模塊,將這個模塊添加到 classpath中。
栗子:

HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).GET().build();
HttpResponse<String> response = client.send(req, 
HttpResponse.BodyHandler.asString());
System.out.println(response.statusCode());
System.out.println(response.version().name());
System.out.println(response.body());

10、其它特性

Deprecated 廢棄了相關 API

Java 9 廢棄或者移除了幾個不常用的功能。其中最主要的是
Applet API,現在是標記爲廢棄的。隨着對安全要求的提高,主流瀏
覽器已經取消對 Java 瀏覽器插件的支持

智能 Java 編譯工具

智能 java 編譯工具( sjavac )的第一個階段始於 JEP139 這個項目,用於在多核處理器情況下提升 JDK 的編譯速度

JDK 9 還更新了 javac 編譯器以便能夠將 java 9 代碼編譯運行在低版本 Java 中

統一的 JVM 日誌系統

javadoc 的 HTML 5 支持

Nashorn 項目在 JDK 9 中得到改進,它爲 Java 提供輕量級的Javascript 運行時。
JDK 9 包含一個用來解析 Nashorn 的 ECMAScript 語法樹的API。這個 API 使得 IDE 和服務端框架不需要依賴 Nashorn 項目的內部實現類,就能夠分析 ECMAScript 代碼。

Javascript 引擎升級:Nashorn(該引擎在8中首次引入,非常好用)

java 的動態編譯器

JIT(Just-in-time)編譯器可以在運行時將熱點編譯成本地代碼,
速度很快。但是 Java 項目現在變得很大很複雜,因此 JIT 編譯器需
要花費較長時間才能熱身完,而且有些 Java 方法還沒法編譯,性能
方面也會下降。AoT 編譯就是爲了解決這些問題而生的

JIT是個很大的研究課題,阿里有專門的團隊搞這一塊

最後:

Java9有一個重大的變化,就是垃回收器默認採用了G1。

Java 9 移除了在 Java 8 中 被廢棄的垃圾回收器配置組合,同時把G1設爲默認的垃圾回收器實現。替代了之前默認使用的Parallel GC,對於這個改變,evens的評論是醬紫的:這項變更是很重要的,因爲相對於Parallel來說,G1會在應用線程上做更多的事情,而Parallel幾乎沒有在應用線程上做任何事情,它基本上完全依賴GC線程完成所有的內存管理。這意味着切換到G1將會爲應用線程帶來額外的工作,從而直接影響到應用的性能

CMS收集器與G1收集器的區別等。

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