Java 9 新特性概覽

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

更新日志

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

pre-reade&本文涉及的內容

首先,你可以在Java 9 Download下載java 9抱虐,然后就可以體驗java 9了。本文是對java 9新特性的概覽而不是詳解茬缩,因為要詳解的話需要收集大量的信息庙睡,而且有可能還不能覆蓋所有特性,還有一點是本人才疏學淺砰逻,未免對新事物的理解過于遲鈍,所以不太可能很快理解java 9中的新特性泛鸟,比如java 9為什么要有某個特性蝠咆,為什么增加這個特性,為什么刪除了某個東西北滥,這些都需要長期的技術積累和實踐刚操,從實際項目中來發(fā)現(xiàn)這些需求。本文涉及的java 9的新特性有一些會多講一些篇幅再芋,有一些會一帶而過菊霜,比如本文比較在意的新增的API,會寫一些示例代碼來體驗济赎,而對于比較底層的JVM優(yōu)化等內容不會涉及太多(無能為力鉴逞,慢慢補上吧!)联喘。下面先將本文的主要內容做一下索引华蜒。

  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已經(jīng)足夠強大豁遭,但是java 9應該比java 8 要更強大叭喜,并且java的發(fā)版在未來會加快速度,需要快速學習啊蓖谢。對于java 9 更為詳細的描述應該參考更多的資料捂蕴,最好可以結合jdk源碼(或者openjdk源碼)來看更好。

Java 9 新特性

Java Modular System

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

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

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

  • JEP 261: Module System腕够,實現(xiàn)模塊化系統(tǒng)级乍;
  • JEP 200: The Modular JDK,將JDK自身進行模塊化帚湘;
  • JEP 201: Modular Source Code玫荣,按照模塊化的形式,重構源代碼,因為現(xiàn)有代碼并不是劃分到一個一個的模塊里的大诸。
  • 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 中的具體體現(xiàn)契吉,下面先看一張圖:

java 9 模塊依賴圖

這是jdk現(xiàn)在的模塊依賴關系圖跳仿,可以發(fā)現(xiàn)所有的模塊都是依賴一個模塊叫做java.base,而java.base中包含了java語言層面的一些基礎包捐晶,具體的java.base的詳情可以參考Module java.base菲语。介于該部分內容是java 9中的主要特性,但過于復雜惑灵,以至于都有專門的書籍來介紹這部分內容山上,所以更為細節(jié)的內容可以參考書籍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文件尤慰,里面描述模塊的依賴關系勾邦,并且只有在模塊暴露了出去,其他模塊才能引用該模塊「钤瘢現(xiàn)在來看看上面三個模塊的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來實現(xiàn)這種模塊編程趾代,比如在
IDEA中,就可以很方便的實現(xiàn)丰辣。java 9中的模塊系統(tǒng)也沒有這么簡單撒强,介于還沒有完全理解,該特性的描述就到此結束吧笙什。

Enhance Process API

Process API提供了一種java程序和操作系統(tǒng)交互的能力飘哨,我們可以在代碼中來獲取關于進程的一些信息,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類的具體實現(xiàn)淘正。

Enhance Collection API

在java 9中摆马,分別為List、Set鸿吆、Map增加了of靜態(tài)工廠方法囤采,來獲取一個不可變的List、Set惩淳、Map蕉毯。下面展示了java 9為List提供的of靜態(tài)工廠方法集,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的話代虾,可以使用下面的方法來實現(xiàn):


        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開發(fā)者方便的使用計算機的并行能力來快速計算棉磨,關于java 8中的Stream的分析總結,可以參考文章Java Streams API学辱,以及Java Stream的并行實現(xiàn)乘瓤。Stream API的并行實現(xiàn)借助了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ài)方法的作用非常有限钙畔,它將對元素T進行判斷,如果是null妆偏,則返回一個空流刃鳄,否則,返回一個只包含一個元素T的流钱骂。而新增的iterate方法類似于for循環(huán)叔锐,類似于下面的代碼:


   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條件來說慧邮,他們兩個方法返回的內容正好
      是整個流的內容调限,他們的區(qū)別在于,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方法的具體實現(xiàn):


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

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


/**
     * 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的實現(xiàn)慧耍,在java 9中,你已經(jīng)可以將一個Optional直接轉換為一個Stream了丐谋,下面是它的實現(xiàn)細節(jié):


    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并發(fā)大師Doug Lea,所以性能問題不需要擔心吏饿,例外一點是踪危,因為這些Reactive的內容添加到了java 語言中,所以比起第三方類庫(比如RxJava)來說更為安全和穩(wěn)定猪落,來看看涉及的幾個類:


Flow
  Publisher
  Subscriber
  Subscription
  Processor
SubmissionPublisher

更為具體和深入的分析將在例外的文章中進行贞远。本文點到為止,還有笨忌,畢竟出自并發(fā)大師之手蓝仲,日后值得研究一番啊官疲!

Private Methods of Interface

在java 8中袱结,接口中可以有默認方法和靜態(tài)方法的實現(xiàn),但是還不支持private方法的實現(xiàn)途凫,而在java 9中垢夹,我們可以在接口中實現(xiàn)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中的默認實現(xiàn)颖榜。private方法和default和靜態(tài)方法的區(qū)別在于棚饵,default方法和靜態(tài)方法都是對外暴露的接口方法,而private方法是私有的掩完,外部調用方是沒有權限知道的噪漾。關于接口的不斷更新,需要更為深入的討論且蓬,再次先不做總結描述欣硼。

Java Shell Support(REPL)

現(xiàn)在,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

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

java 9 javadoc

Other Details

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

本文簡單分析了java 9的新特性况毅,更為完整深入的java 9的特性應該搜集更多的資料來總結分蓖,關于是否要將目前的java版本升級到java 9,我的想法是俭茧,應該等等咆疗,一個原因是java 9和java 8比起來貌似沒有太多性能優(yōu)化方面的考慮(不包括我沒有提到了jvm層面的優(yōu)化,那些優(yōu)化任何一個版本的java升級都會做大量的優(yōu)化的)母债,僅類庫層面來說午磁,java 9貌似沒有太多的兩點,新增的類好像不多毡们,多數(shù)是對原有類的增強迅皇,但是貌似這些增強可有可無啊(個人覺得)衙熔。還有一個原因是登颓,未來java的發(fā)版周期將更短,而java 9才剛發(fā)布不久红氯,應該做一些深入的調研測試框咙,等時機成熟再升級java 8到java 9也不遲~但是,如果目前還在使用java 8以前版本的javaer來說痢甘,我強烈建議升級到java 8喇嘱,因為這個版本的java亮點很多,并且各方面表現(xiàn)都是很不錯的塞栅,至于java 9者铜,看各自的調研結論吧!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市作烟,隨后出現(xiàn)的幾起案子愉粤,更是在濱河造成了極大的恐慌,老刑警劉巖拿撩,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衣厘,死亡現(xiàn)場離奇詭異,居然都是意外死亡压恒,警方通過查閱死者的電腦和手機头滔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涎显,“玉大人,你說我怎么就攤上這事兴猩∑谙牛” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵倾芝,是天一觀的道長讨勤。 經(jīng)常有香客問我,道長晨另,這世上最難降的妖魔是什么潭千? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮借尿,結果婚禮上刨晴,老公的妹妹穿的比我還像新娘。我一直安慰自己路翻,他們只是感情好狈癞,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著茂契,像睡著了一般蝶桶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掉冶,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天真竖,我揣著相機與錄音,去河邊找鬼厌小。 笑死恢共,一個胖子當著我的面吹牛,可吹牛的內容都是我干的召锈。 我是一名探鬼主播旁振,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拐袜?” 一聲冷哼從身側響起吉嚣,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹬铺,沒想到半個月后尝哆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡甜攀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年秋泄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片规阀。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恒序,死狀恐怖,靈堂內的尸體忽然破棺而出谁撼,到底是詐尸還是另有隱情歧胁,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布厉碟,位于F島的核電站喊巍,受9級特大地震影響,放射性物質發(fā)生泄漏箍鼓。R本人自食惡果不足惜崭参,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望款咖。 院中可真熱鬧何暮,春花似錦、人聲如沸铐殃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽背稼。三九已至贰军,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蟹肘,已是汗流浹背词疼。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帘腹,地道東北人贰盗。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像阳欲,于是被迫代替她去往敵國和親舵盈。 傳聞我的和親對象是個殘疾皇子陋率,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容