Java 9 新特性概覽

作者: 一字馬胡
轉載標志 【2017-11-03】

更新日志

日期 更新內容 備注
2017-11-03 添加轉載標志 持續更新

pre-reade&本文涉及的內容

首先,你可以在Java 9 Download下載java 9,然后就可以體驗java 9了。本文是對java 9新特性的概覽而不是詳解,因為要詳解的話需要收集大量的信息,而且有可能還不能覆蓋所有特性,還有一點是本人才疏學淺,未免對新事物的理解過于遲鈍,所以不太可能很快理解java 9中的新特性,比如java 9為什么要有某個特性,為什么增加這個特性,為什么刪除了某個東西,這些都需要長期的技術積累和實踐,從實際項目中來發現這些需求。本文涉及的java 9的新特性有一些會多講一些篇幅,有一些會一帶而過,比如本文比較在意的新增的API,會寫一些示例代碼來體驗,而對于比較底層的JVM優化等內容不會涉及太多(無能為力,慢慢補上吧!)。下面先將本文的主要內容做一下索引。

  1. Java Modular System
  2. Enhance Process API
  3. Enhance Collection API
  4. Enhance Streams API
  5. Enhance Optional API
  6. Reactive API Support(RxJava)
  7. Private Methods of Interface
  8. Java Shell Support(REPL)
  9. Enhance Javadoc(search)
  10. Other Details

本文將基于上面提到的10點內容對java 9的新特性進行淺讀解讀,Java 8已經足夠強大,但是java 9應該比java 8 要更強大,并且java的發版在未來會加快速度,需要快速學習啊。對于java 9 更為詳細的描述應該參考更多的資料,最好可以結合jdk源碼(或者openjdk源碼)來看更好。

Java 9 新特性

Java Modular System

Java 9 一個比較大的改動就是增加了模塊系統,基于 Jigsaw [?d??gs?:] 項目,這是一個較為龐大復雜的項目,它的目標主要是下面兩點:

  • 可靠的配置:明確模塊邊界和模塊之間的依賴關系
  • 強封裝性:通過封裝模塊內部私有細節,來避免不希望發生的依賴關系,也能避免一些安全問題等。

而Jigsaw被拆分為下面幾個具體的項目:

  • JEP 261: Module System,實現模塊化系統;
  • JEP 200: The Modular JDK,將JDK自身進行模塊化;
  • JEP 201: Modular Source Code,按照模塊化的形式,重構源代碼,因為現有代碼并不是劃分到一個一個的模塊里的。
  • JEP 220: Modular Run-Time Images,重新設計JDK和JRE的結構,定義新的URI scheme操作模塊,類和資源(jrt)。
  • JEP 260: Encapsulate Most Internal APIs,按照模塊化封裝性的要求,將不希望暴露的內部API封裝起來,如果確實證明是廣泛需要的,就作為公共API公開出來。
  • JEP 282: jlink: The Java Linker。新的link工具

所謂JEP(JDK Enhancement Proposals),是java 9 中為了管理新特性而引入的代號。為了快速了解Jigsaw 項目在java 9 中的具體體現,下面先看一張圖:

java 9 模塊依賴圖

這是jdk現在的模塊依賴關系圖,可以發現所有的模塊都是依賴一個模塊叫做java.base,而java.base中包含了java語言層面的一些基礎包,具體的java.base的詳情可以參考Module java.base。介于該部分內容是java 9中的主要特性,但過于復雜,以至于都有專門的書籍來介紹這部分內容,所以更為細節的內容可以參考書籍Java 9 Modularity。下面來看一看如何在我們自己的項目中使用模塊化編程呢。

比如,我們有三個模塊,一個模塊叫做com.hujian.base,提供一些基礎信息內容,而第二個模塊叫做com.hujian.extra,提供一些擴展信息,第三個模塊叫做com.hujian.info,來提供較為全面的信息,他們之間的依賴關系為:com.hujian.extra依賴于com.hujian.base,而com.hujian.info依賴了com.hujian.base和com.hujian.extra。在java 9中,我們需要在每個模塊中寫一個module-info.java文件,里面描述模塊的依賴關系,并且只有在模塊暴露了出去,其他模塊才能引用該模塊。現在來看看上面三個模塊的module-info.java應該怎么寫:


對于com.hujian.base來說,它沒有依賴其他模塊,所以不需要依賴,但是,它需要提供服務,也就是
其他模塊會引用該模塊,所以他需要將自己的模塊暴露出去,下面是它的module-info.java文件的內容:

 module com.hujian.base {

    exports com.hujian.base; //將模塊暴露出去

}

而對于com.hujian.extra來說,它需要依賴com.hujian.base模塊,并且com.hujian.info模塊
會引用該模塊,所以它的module-info.java是這樣的:

 module com.hujian.extra {

    requires com.hujian.base;

    exports com.hujian.extra;

}

最后是com.hujian.info模塊,它的module-info.java應該這樣寫:

 module com.hujian.info {

    requires com.hujian.base;
    require com.hujian.extra;

}

當然,這只是編寫了module-info.java文件,實際的工作要比這個更多,但是我們可以借助IDE來實現這種模塊編程,比如在
IDEA中,就可以很方便的實現。java 9中的模塊系統也沒有這么簡單,介于還沒有完全理解,該特性的描述就到此結束吧。

Enhance Process API

Process API提供了一種java程序和操作系統交互的能力,我們可以在代碼中來獲取關于進程的一些信息,java 9中新增了一個類ProcessHandle,使用這個類可以很方便的查詢進程的一些信息。下面是該類的使用示例:


package com.hujian.java9;

import java.util.function.Consumer;

/**
 * Created by hujian06 on 2017/10/28.
 *
 * ProcessHandle demo
 */
public class ProcessHandleDemo {

    public static void main(String ... args) {

        long pid = ProcessHandle.current().pid();

        ProcessHandle.allProcesses()
                .forEach(new Consumer<ProcessHandle>() {
                    @Override
                    public void accept(ProcessHandle processHandle) {
                        if (processHandle.pid() == pid) {
                            System.out.println("Current Process:" + pid + "\n" +
                                    processHandle.info());
                        }
                    }
                });
    }
}


上面的例子僅僅是獲取了當前進程的進程id,更為有趣的應用可以參考ProcessHandle類的具體實現。

Enhance Collection API

在java 9中,分別為List、Set、Map增加了of靜態工廠方法,來獲取一個不可變的List、Set、Map。下面展示了java 9為List提供的of靜態工廠方法集,Set和Map都是類似的就不贅述了:


static <E> List<E> of()
static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
static <E> List<E> of(E e1, E e2, E e3)
static <E> List<E> of(E e1, E e2, E e3, E e4)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> List<E> of(E... elements)

在java 9之前,如果我們想要獲取一個不可變的List的話,可以使用下面的方法來實現:


        List<String> emptyList = Collections.emptyList();

        List<String> list = Collections.singletonList("java 9");

而在java 9中,只需要使用of就可以獲取一個不可變的List,使用方法如下:


        List<String> emptyStringList = List.of();
        List<String> stringList = List.of("java 7", "java 8", "java 9");

Enhance Streams API

java 8中新增的Stream API可以讓java開發者方便的使用計算機的并行能力來快速計算,關于java 8中的Stream的分析總結,可以參考文章Java Streams API,以及Java Stream的并行實現。Stream API的并行實現借助了Fork/Join并行框架,關于Fork/Join的介紹,可以參考文章Java Fork/Join并行框架。而在java 9中,Stream API新增了幾個方法,下面展示了這些新增的方法:


default Stream<T> dropWhile(Predicate<? super T> predicate)
default Stream<T> takeWhile(Predicate<? super T> predicate)
static <T> Stream<T> ofNullable(T t)
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)

dropWhile方法和takeWhile方法是一對類似的方法,這兩個方法適合用在有序流,而對于無序流來說,使用這兩個方法會造成不可預料的結果。而ofNullable靜態方法的作用非常有限,它將對元素T進行判斷,如果是null,則返回一個空流,否則,返回一個只包含一個元素T的流。而新增的iterate方法類似于for循環,類似于下面的代碼:


   for (T index=seed; hasNext.test(index); index = next.apply(index)) {
        //todo...
   }

下面是使用iterate這個新方法來生成一個流的示例代碼:


        Stream.iterate( 0, n -> (n <= 100), n -> n + 1 )
                .forEach(System.out::println);

需要注意的是,只要test返回false,那么就會停止向前,這一點需要特別注意。下面來看一下dropWhile方法和takeWhile方法的使用示例以及他們的注意事項:


        Stream.of(1, 2, 3, 4)
                .takeWhile(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) {
                        return integer < 4;
                    }
                }).forEach(System.out::println);
                
        對于takeWhile來說,它會從第一個元素進行test,如果第一個元素test返回false,那么就會立刻返回整個流。
        否則,會一直test到第一個返回false的元素,然后截取前面這一段返回。
        
               Stream.of(1, 2, 3, 4)
                .dropWhile(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) {
                        return integer < 4;
                    }
                }).forEach(System.out::println);         

      dropWhile類似于是takeWhile的互補操作,對于同一個有序流,同一個test條件來說,他們兩個方法返回的內容正好
      是整個流的內容,他們的區別在于,takeWhile是返回滿足條件的流內容,而dropWhile將丟棄滿足條件的流,返回的
      正是不滿足條件的流。

Enhance Optional API

Optional類也是java 8新增的類,在java 9中對他有一些增強,新增了三個方法:


public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
public Stream<T> stream()

首先是ifPresentOrElse方法,這個方法是對原來的方法ifPresent的增強,下面是ifPresentOrElse方法的具體實現:


    public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
        if (value != null) {
            action.accept(value);
        } else {
            emptyAction.run();
        }
    }

可以看到,ifPresentOrElse方法在value為null的時候提供了例外的操作,這也是orElse的語義。接下來看新增的or方法,下面是整個方法的實現,以及對這個方法的描述:


/**
     * If a value is present, returns an {@code Optional} describing the value,
     * otherwise returns an {@code Optional} produced by the supplying function.
     *
     * @param supplier the supplying function that produces an {@code Optional}
     *        to be returned
     * @return returns an {@code Optional} describing the value of this
     *         {@code Optional}, if a value is present, otherwise an
     *         {@code Optional} produced by the supplying function.
     * @throws NullPointerException if the supplying function is {@code null} or
     *         produces a {@code null} result
     * @since 9
     */
    public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
        Objects.requireNonNull(supplier);
        if (isPresent()) {
            return this;
        } else {
            @SuppressWarnings("unchecked")
            Optional<T> r = (Optional<T>) supplier.get();
            return Objects.requireNonNull(r);
        }
    }

最為激動人心的應該是第三個方法stream,它提供了將Optional轉換為Stream的實現,在java 9中,你已經可以將一個Optional直接轉換為一個Stream了,下面是它的實現細節:


    public Stream<T> stream() {
        if (!isPresent()) {
            return Stream.empty();
        } else {
            return Stream.of(value);
        }
    }

Reactive API Support(RxJava)

如果你接觸過RxJava,那么就很好理解java 9中新增的Reactive內容了,下面首先展示了一個非常簡單的使用示例:


package com.hujian.java9;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;
import java.util.concurrent.SubmissionPublisher;

public class FlowDemo2 {
    private static final ExecutorService SERVICE = Executors.newFixedThreadPool(1);
    private static final int CAPATIAL = 1024;

    public static void main(String[] args) {
        // Create a publisher.
        SubmissionPublisher<String> publisher = new SubmissionPublisher<>(SERVICE, CAPATIAL);

        // Create a subscriber and register it with the publisher.
        MySubscriber<String> subscriber = new MySubscriber<>();
        publisher.subscribe(subscriber);

        // Publish several data items and then close the publisher.
        List.of("Java 7", "Java 8", "Java 9")
                .forEach(item -> publisher.submit(item));

        publisher.close();

        SERVICE.submit(() -> {
            //wait the publish job~
        });

        SERVICE.shutdownNow();

    }

    static class MySubscriber<T> implements Subscriber<T> {

        @Override
        public void onSubscribe(Subscription subscription) {
            subscription.request(3);
            System.out.println("<start to publish item>");
        }

        @Override
        public void onNext(T item) {
            System.out.println("<Received>:" + item);
        }

        @Override
        public void onError(Throwable t) {
            t.printStackTrace();
        }

        @Override
        public void onComplete() {
            System.out.println("<onComplete>");
        }
    }
}

下面是涉及Reactive的幾個新增的類,需要說明的一點是,這些內容出自java并發大師Doug Lea,所以性能問題不需要擔心,例外一點是,因為這些Reactive的內容添加到了java 語言中,所以比起第三方類庫(比如RxJava)來說更為安全和穩定,來看看涉及的幾個類:


Flow
  Publisher
  Subscriber
  Subscription
  Processor
SubmissionPublisher

更為具體和深入的分析將在例外的文章中進行。本文點到為止,還有,畢竟出自并發大師之手,日后值得研究一番啊!

Private Methods of Interface

在java 8中,接口中可以有默認方法和靜態方法的實現,但是還不支持private方法的實現,而在java 9中,我們可以在接口中實現private方法了,先看下面的示例:


package com.hujian.java9;

/**
 * Created by hujian06 on 2017/10/28.
 *
 * demo of interface
 *
 */
public class InterfeaceDemo {

    public static void main(String ... args) {

        A a = new A() {
            @Override
            public void af() {
                f();
            }
        };

        a.af();
    }

}

interface A {

    String finalString = "Tag";

    void af();

    default void f() {
        f1();
    }

    private void f1() {
        System.out.println(finalString + ":f1");
    }

}

f1是接口A中的默認實現。private方法和default和靜態方法的區別在于,default方法和靜態方法都是對外暴露的接口方法,而private方法是私有的,外部調用方是沒有權限知道的。關于接口的不斷更新,需要更為深入的討論,再次先不做總結描述。

Java Shell Support(REPL)

現在,java語言也支持REPL了,就像下面展示的圖片一樣:

JShell

Enhance Javadoc(search)

參考:Java? Platform, Standard Edition & Java Development Kit
Version 9 API Specification

以及java 8版本的javadoc:Java? Platform, Standard Edition 8
API Specification

區別還是很明顯的,java 9開始javadoc支持查找了,這一點是很明智的!下面看一下搜索效果圖,這樣是不是很快可以找到我們需要查找的類信息呢:

java 9 javadoc

Other Details

  1. 對CompletableFuture類的增強,細節看代碼吧!
  2. "_"不再可以是一個標志符,在java 9中已經升級為一個關鍵字了!
  3. HTTP/2 Client API(孵化,目前來看還是用不了啊,好像需要重新編譯openjdk?),據說比Apache的HttpClients性能還要好啊,這一點很有吸引力啊,還是比較期待的
  4. 其他更改,可以參考

本文簡單分析了java 9的新特性,更為完整深入的java 9的特性應該搜集更多的資料來總結,關于是否要將目前的java版本升級到java 9,我的想法是,應該等等,一個原因是java 9和java 8比起來貌似沒有太多性能優化方面的考慮(不包括我沒有提到了jvm層面的優化,那些優化任何一個版本的java升級都會做大量的優化的),僅類庫層面來說,java 9貌似沒有太多的兩點,新增的類好像不多,多數是對原有類的增強,但是貌似這些增強可有可無啊(個人覺得)。還有一個原因是,未來java的發版周期將更短,而java 9才剛發布不久,應該做一些深入的調研測試,等時機成熟再升級java 8到java 9也不遲~但是,如果目前還在使用java 8以前版本的javaer來說,我強烈建議升級到java 8,因為這個版本的java亮點很多,并且各方面表現都是很不錯的,至于java 9,看各自的調研結論吧!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,818評論 18 139
  • Java 8可謂是自Java 5以來最具革命性的版本了,她在語言、編譯器、類庫、開發工具以及Java虛擬機等方面都...
    光劍書架上的書閱讀 1,612評論 0 13
  • JDK各個版本的新特性 對于很多剛接觸java語言的學者來說,要了解一門語言,最好的方式是從基礎的版本進行理解,升...
    小莊bb閱讀 1,119評論 0 1
  • 黑墻白瓦轉過,青綠的藤蔓就攸地跳入眼簾. 四月至 江南的青山綠水也露出圓潤而多情的一角.江南好,只是對我,鶯歌燕舞...
    貓本克里斯閱讀 238評論 0 0
  • 1 曉曉說,你是不是還記得他? 我笑了笑,曉曉問得太巧妙了。 不是還沒忘記他,而是還記得他。 我說,你知道的,我記...
    貓爾夜閱讀 376評論 0 1