閱讀192 返回首頁    go 技術社區[雲棲]


Java 9的14個新特性總結

Java 9 包含了豐富的特性集。雖然Java 9沒有新的語言概念,但是有開發者感興趣的新的API和診斷命令。

我們將快速的,著重的瀏覽其中的幾個新特性;?

模塊化係統?Jigsaw 項目

模塊化是一個很通用的概念。在軟件中,模塊化可以運用到編寫和實現一個程序和計算係統,他們都是作為獨立的模塊,而不是作為一個單一的和完整的設計。

Java 9中主要的變化是已經實現的模塊化係統。模塊化的引入使得JDK可以在更小的設備中使用。采用模塊化係統的應用程序隻需要這些應用程序所需的那部分JDK模塊,而非是整個JDK框架了。模塊化係統也可以將公共的類封裝到一個模塊中。因此一個封裝在模塊中的定義為public的類不能再任何地方使用,除非一個模塊顯式的定義了這個模塊。由於Java 9的這個變化,Java內部的API(例如com.sun.*)默認情況下是不能使用的。

簡而言之,所有的模塊將需要在所謂的module-info.java文件中進行描述,這個文件是位於Java代碼結構的頂層。

如果你想學習Java可以來這個群,首先是二二零,中間是一四二,最後是九零六,裏麵有大量的學習資料可以下載。

module me.aboullaite.java9.modules.car {
    requires me.aboullaite.java9.modules.engines;//依賴的模塊
    exports me.aboullaite.java9.modules.car.handling;//在模塊中導出包
}

我們的模塊car(汽車)需要依賴+模塊engine(引擎)和需要導出handling(操縱)包。

需要更多深入的例子可以查看OpenJDK中項目Jigsaw:模塊化係統快速入門

JShell?Java 9 REPL

你可能問:“REPL是什麼”?REPL是一種快速運行語句的命令行工具。

在Java中,如果你想執行一個簡單的語句,我們要麼創建一個帶main方法的類,要麼創建一個可以執行的Test類。當你正在啟動Java程序的時候,如果你想執行某些語句並且想立刻看見執行結果,上麵的做法看起來不是那麼有用了。

JShell試圖去解決這個問題。Java開發者可以利用JShell在沒有創建類的情況下直接聲明變量,計算表達式,執行語句。JShell也可以從文件中加載語句或者將語句保存到文件中。並且JShell也可以是tab鍵進行自動補全的特性。

集合工廠方法

在Java 9之前,Java隻能利用一些實用方法(例如:Collections.unmodifiableCollection(Collection<? extends T> c))創建一個不可修改視圖的集合。例如,我們可以在Java 8中使用一條如下所示的語句,創建一個Collection的不可修改的視圖。雖然這是最簡單的創建方式,但是看起來很糟糕!不是嗎?

Map<String, String> immutableMap =
Collections.unmodifiableMap(
            new HashMap<String, String>() {{
                put("key1", "Value1");
                put("key2", "Value2");
                put("key3", "Value3");
            }});

現在,Java 9引入了一些有用的工廠方法來創建不可修改的集合。我們現在在Java 9中創建不可修改的Map集合,如下所示。

Map<String, String> immutableMap = Map.of("key1", "Value1", "key2", "Value2","key3", "Value3");

下麵是工廠方法的例子:

 // empty immutable collections 不可修改的空集合
List<String> emptyImmutableList = List.of();
Set<String> emptyImmutableSet = Set.of();
Map emptyImmutableMap = Map.of();

// immutable collections 不可修改的集合
List<String> immutableList = List.of("one", "two");
Set<String> immutableSet = Set.of("value1", "value2");
Map<String, String> immutableMap = Map.of("key1", "Value1", "key2", "Value2", "key3", "Value3");

接口中的私有方法

Java 8的接口引入了默認方法和靜態方法。雖然Java 8首次計劃實現接口的私有方法,卻是在Java 9中實現。默認方法和靜態方法可以共享接口中的私有方法,因此避免了代碼冗餘,這也使代碼更加清晰。如果私有方法是靜態的,那這個方法就屬於這個接口的。並且沒有靜態的私有方法隻能被在接口中的實例調用。

interface InterfaceWithPrivateMethods {
    private static String staticPrivate() {
        return "static private";    
    }

    private String instancePrivate() {
        return "instance private";
    }

    default void check() {
        String result = staticPrivate();

        InterfaceWithPrivateMethods pvt = new InterfaceWithPrivateMethods() {
            // anonymous class 匿名類
        };

        result = pvt.instancePrivate();
    }

}

響應式流

JDK9中的Flow API對應響應式流規範,響應式流規範是一種事實標準。JEP 266包含了一組最小接口集合,這組接口能捕獲核心的異步發布與訂閱。希望在未來第三方能夠實現這些接口,並且能共享其方式。

java.util.concurrent.Flow包含以下4個接口:

*?Flow.Processor(處理器)

*?Flow.Publisher(發布者)

*?Flow.Subscriber(訂閱者)

*?Flow.Subscription(訂閱管理器)

這些接口都支持響應式流發布-訂閱框架。Java 9也提供了實用類SubmissionPublisher。一個發布者產生一個或多個物品,這些物品由一個或多個消費者消耗。並且訂閱者由訂閱管理器管理。訂閱管理器連接發布者和訂閱者。

多分辨率圖像API?JEP 251

目標是定義多分辨率圖像API,這樣開發者就能很容易的操作和展示不同分辨率的圖像了。

這個新的API定義在java.awt.image包中,這個API能給我們帶來如下的幫助:

* 將不同分辨率的圖像封裝到一張(多分辨率的)圖像中,作為它的變體。

* 獲取這個圖像的所有變體。

* 獲取特定分辨率的圖像變體?表示一張已知分辨率單位為DPI的特定尺寸大小的邏輯圖像,並且這張圖像是最佳的變體。

基於當前屏幕分辨率大小和運用的圖像轉換算法,java.awt.Graphics類可以從接口MultiResolutionImage獲取所需的變體。java.awt.image.AbstractMultiResolutionImage類提供了ava.awt.image.AbstractMultiResolutionImage?默認實現。AbstractMultiResolutionImage的基礎實現是java.awt.image.BaseMultiResolutionImage

進程API的改進

迄今為止,通過Java來控製和管理操作係統的進程的能力有限。例如,為了做一些簡單的事情,像獲取進程的PID,你要麼需要訪問本地代碼,要麼使用某種臨時解決方案。不僅如此,每個(係統)平台需要一個不同實現來確保你能獲得正確的結果。

在Java 9中,期望代碼能獲取Linux PID,現在是如下方式:

public static void main(String[] args) throws Exception
{
  Process proc = Runtime.getRuntime().exec(new String[]{ "/bin/sh", "-c", "echo $PPID" });

  if (proc.waitFor() == 0)
   {
    InputStream in = proc.getInputStream();
    int available = in.available();
    byte[] outputBytes = new byte[available];

    in.read(outputBytes);
    String pid = new String(outputBytes);

    System.out.println("Your pid is " + pid);
   }
}

你可以變換如下的方式(同樣支持所有的操作係統):

System.out.println("Your pid is " + Process.getCurrentPid());

Try-With-Resources

在Java 7中,try-with-resouces語法要求為每一個資源聲明一個新的變量,而且這些資源由try-with-resources語句進行管理。

在就Java 9中,有另外一個改進:如果一個資源被final或者等效於final變量引用,則在不需要聲明一個新的變量的情況下,try-with-resources就可以管理這個資源。

MyAutoCloseable mac = new MyAutoCloseable();
try (mac) {
   // do some stuff with mac
}

try (new MyAutoCloseable() { }.finalWrapper.finalCloseable) {
  // do some stuff with finalCloseable
}

鑽石(diamond)操作符範圍的延伸

Java 7給出的鑽石操作符使我們編寫代碼更簡單了。在下麵的例子中,你可以看見Java 7中List(列表)的可讀性更強了,並且使代碼更加的簡潔了。

List<String> preJava7 = new ArrayList<String>();//java 7 之前的寫法
List<String> java7 = new ArrayList<>();//java 7 之後的寫法

但是Java 7中鑽石操作符不允許在匿名類上使用。但在Java 9中改善了這一情況,允許鑽石操作符在匿名類上使用。下麵的例子隻有在Java 9中才能通過編譯。

List<String> list = new ArrayList<>(){ };

增強的注釋Deprecated

注釋@Deprecated可以標記Java API。注釋@Deprecated有很多種含義,例如它可以表示在不遠的將來的某個時間,被標記的API將會被移除。它也可以表示這個API已經被破壞了,並不應該再被使用。它還有其它很多含義。為了提供更多有關@Deprecated的信息,@Deprecated添加了forRemoval元素和since元素。

Java SE 9 中也提供了掃描jar文件的工具jdeprscan。這款工具也可以掃描一個聚合類,這個類使用了Java SE中的已廢棄的API元素。 這個工具將會對使用已經編譯好的庫的應用程序有幫助,這樣使用者就不知道這個已經編譯好的庫中使用了那些已廢棄的API。

統一的JVM日誌

如今,我們很難知道導致JVM性能問題和導致JVM崩潰的根本原因。解決這個問題的一個方法是對所有的JVM組件引入一個單一的係統,這些JVM組件支持細粒度的和易配置的JVM日誌。目前,不同的JVM組件對於日誌使用的是不同的機製和規則,這使得JVM難以進行調試。

注釋SafeVarargs範圍的延伸

直到Java 8,@SafeVarargs才能在靜態方法、final方法和構造器上使用。但是這些方法或者構造器是不能被覆蓋的。這些方法中缺少另一個不能被覆蓋的方法,這個方法就是私有方法。Java 9可以將@SafeVarargs添加到私有方法上。下麵的例子在Java 9中是正確的,但是在Java 8中就會拋出編譯時錯誤:注釋@SafeVarargs不能在非final的實例方法iAmSafeVaragrsMethod上使用

@SafeVarargs
  private void iAmSafeVaragrsMethod(String... varagrgs)
  {
     for (String each: varagrgs) {
        System.out.println(each);
     }
  }

HTTP 2 客戶端

Java 9采用了全新的HTTP客戶端API,這些API支持HTTP/2協議和WebSocket協議,並且替換了遺留的HTTPURLConnectionAPI。這些改變並不應該在Java 9中完成。這些API可以從Incubator(孵化器)模塊中獲取。因此在默認情況下,這個模塊是不能根據classpath獲取的,需要使用--add-modules命令選項配置這個模塊,將這個模塊添加到classpath中。

我們創建一個HTTPRequest請求和獲取異步的響應:

 URI testPageURI = new URI("https://127.0.0.1:8080/testPage");
  CompletableFuture<HttpResponse> nonBlockingResponse =  HttpRequest
          .create(testPageURI)
          .GET().responseAsync();
  int tries = 0;
  while(!nonBlockingResponse.isDone() && tries++ < 5) { Thread.sleep(5); } if (nonBlockingResponse.isDone()) { HttpResponse response = nonBlockingResponse.get(); System.out.println("status code : " + response.statusCode() + " --> " +  response.body(HttpResponse.asString()));
  }
  else {
      nonBlockingResponse.cancel(true);
      System.out.println("Cancelling, could not get response");
  }

HTML5風格的Java幫助文檔

Java 8以及之前的版本生成的Java幫助文檔是在HTML 4中,而HTML 4已經是很久的標準了。在Java 9中,javadoc命令行中選項部分添加了輸出選項,這個選項的值要麼是HTML 4,要麼是HTML 5。現在HTML 4是默認的輸出標記語言,但是在之後發布的JDK中,HTML 5將會是默認的輸出標記語言。Java幫助文檔還是由三個框架組成的結構構成,這是不會變的,並且以HTML 5輸出的Java幫助文檔也保持相同的結構。

更多的特性

* 保留下劃線字符。變量不能被命名為_

* 廢棄Applet API;

*?javac不再支持Java1.4以及之前的版本;

* 廢棄Java瀏覽器插件;

* 棧遍曆API?棧遍曆API能過濾和遲訪問在堆棧跟蹤中的信息。

最後更新:2017-05-09 15:02:15

  上一篇:go 篤行出真知,報名參加雲棲大會成都峰會的四大理由
  下一篇:go Java注解處理器使用詳解