天天看點

Java 9新特性

Java 8 釋出三年多之後,已經于在2017年9月21日釋出了。 你可能已經聽說過 Java 9 的子產品系統,但是這個新版本還有許多其它的更新。 這裡有九個令人興奮的新功能。

1. Java 平台級子產品系統

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

子產品化的 JAR 檔案都包含一個額外的子產品描述器。在這個子產品描述器中, 對其它子產品的依賴是通過 “requires” 來表示的。另外, “exports” 語句控制着哪些包是可以被其它子產品通路到的。所有不被導出的包預設都封裝在子產品的裡面。如下是一個子產品描述器的示例,存在于 “module-info.java” 檔案中:

1 2 3 4 5

module blog {

exports com.pluralsight.blog;

requires cms;

}

我們可以如下展示子產品:

Java 9新特性

請注意,兩個子產品都包含封裝的包,因為它們沒有被導出(使用橙色盾牌可視化)。 沒有人會偶然地使用來自這些包中的類。Java 平台本身也使用自己的子產品系統進行了子產品化。通過封裝 JDK 的内部類,平台更安全,持續改進也更容易。

當啟動一個子產品化應用時, JVM 會驗證是否所有的子產品都能使用,這基于 `requires` 語句——比脆弱的類路徑邁進了一大步。子產品允許你更好地強制結構化封裝你的應用并明确依賴。你可以在這個課程中學習更多關于 Java 9 中子產品工作的資訊 。

2. Linking

當你使用具有顯式依賴關系的子產品和子產品化的 JDK 時,新的可能性出現了。你的應用程式子產品現在将聲明其對其他應用程式子產品的依賴以及對其所使用的 JDK 子產品的依賴。為什麼不使用這些資訊建立一個最小的運作時環境,其中隻包含運作應用程式所需的那些子產品呢? 這可以通過 Java 9 中的新的 jlink 工具實作。你可以建立針對應用程式進行優化的最小運作時映像而不需要使用完全加載 JDK 安裝版本。

3. JShell : 互動式 Java REPL

許多語言已經具有互動式程式設計環境,Java 現在加入了這個俱樂部。您可以從控制台啟動 jshell ,并直接啟動輸入和執行 Java 代碼。 jshell 的即時回報使它成為探索 API 和嘗試語言特性的好工具。

Java 9新特性

測試一個 Java 正規表達式是一個很好的說明 jshell 如何使您的生活更輕松的例子。 互動式 shell 還可以提供良好的教學環境以及提高生産力,您可以在此了解更多資訊。在教人們如何編寫 Java 的過程中,不再需要解釋 “public static void main(String [] args)” 這句廢話。

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

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

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

4. 改進的 Javadoc

有時一些小事情可以帶來很大的不同。你是否就像我一樣在一直使用 Google 來查找正确的 Javadoc 頁面呢? 這不再需要了。Javadoc 現在支援在 API 文檔中的進行搜尋。另外,Javadoc 的輸出現在符合相容 HTML5 标準。此外,你會注意到,每個 Javadoc 頁面都包含有關 JDK 子產品類或接口來源的資訊。

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

Java 9新特性

5. 集合工廠方法

通常,您希望在代碼中建立一個集合(例如,List 或 Set ),并直接用一些元素填充它。 執行個體化集合,幾個 “add” 調用,使得代碼重複。 Java 9,添加了幾種集合工廠方法:

1 2

Set<Integer> ints = Set.of(

1

,

2

,

3

);

List<String> strings = List.of(

"first"

,

"second"

);

除了更短和更好閱讀之外,這些方法也可以避免您選擇特定的集合實作。 事實上,從工廠方法傳回已放入數個元素的集合實作是高度優化的。這是可能的,因為它們是不可變的:在建立後,繼續添加元素到這些集合會導緻 “UnsupportedOperationException” 。

在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");           

6. 改進的 Stream API

長期以來,Stream API 都是 Java 标準庫最好的改進之一。通過這套 API 可以在集合上建立用于轉換的申明管道。在 Java 9 中它會變得更好。Stream 接口中添加了 4 個新的方法:dropWhile, takeWhile, ofNullable。還有個 iterate 方法的新重載方法,可以讓你提供一個 Predicate (判斷條件)來指定什麼時候結束疊代:

1

IntStream.iterate(

1

, i -> i <

100

, i -> i +

1

).forEach(System.out::println);

第二個參數是一個 Lambda,它會在目前 IntStream 中的元素到達 100 的時候傳回 true。是以這個簡單的示例是向控制台列印 1 到 99。

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

1

Stream<Integer> s = Optional.of(

1

).stream();

在組合複雜的 Stream 管道時,将 Optional 轉換為 Stream 非常有用。

7. 私有接口方法

Java 8 為我們帶來了接口的預設方法。 接口現在也可以包含行為,而不僅僅是方法簽名。 但是,如果在接口上有幾個預設方法,代碼幾乎相同,會發生什麼情況? 通常,您将重構這些方法,調用一個可複用的私有方法。 但預設方法不能是私有的。 将複用代碼建立為一個預設方法不是一個解決方案,因為該輔助方法會成為公共API的一部分。 使用 Java 9,您可以向接口添加私有輔助方法來解決此問題:

1 2 3 4 5 6 7 8 9 10 11

public

interface

MyInterface {

void

normalInterfaceMethod();

default

void

interfaceMethodWithDefault() {  init(); }

default

void

anotherDefaultMethod() { init(); }

// This method is not part of the public API exposed by MyInterface

private

void

init() { System.out.println(

"Initializing"

); }

}

如果您使用預設方法開發 API ,那麼私有接口方法可能有助于建構其實作。

8. HTTP/2

Java 9 中有新的方式來處理 HTTP 調用。這個遲到的特性用于代替老舊的 `HttpURLConnection` API,并提供對 WebSocket 和 HTTP/2 的支援。注意:新的 HttpClient API 在 Java 9 中以所謂的孵化器子產品傳遞。也就是說,這套 API 不能保證 100% 完成。不過你可以在 Java 9 中開始使用這套 API:

1 2 3 4 5 6 7 8 9

HttpClient client = HttpClient.newHttpClient();

HttpRequest req =

HttpRequest.newBuilder(URI.create(

"http://www.google.com"

))

.header(

"User-Agent"

,

"Java"

)

.GET()

.build();

HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandler.asString());

HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandler.asString());

除了這個簡單的請求/響應模型之外,HttpClient 還提供了新的 API 來處理 HTTP/2 的特性,比如流和服務端推送。

9. 多版本相容 JAR

我們最後要來着重介紹的這個特性對于庫的維護者而言是個特别好的消息。當一個新版本的 Java 出現的時候,你的庫使用者要花費數年時間才會切換到這個新的版本。這就意味着庫得去向後相容你想要支援的最老的 Java 版本 (許多情況下就是 Java 6 或者 7)。這實際上意味着未來的很長一段時間,你都不能在庫中運用 Java 9 所提供的新特性。幸運的是,多版本相容 JAR 功能能讓你建立僅在特定版本的 Java 環境中運作庫程式時選擇使用的 class 版本:

1 2 3 4 5 6 7 8 9

multirelease.jar

├── META-INF

│   └── versions

│       └──

9

│           └── multirelease

│               └── Helper.

class

├── multirelease

├── Helper.

class

└── Main.

class

在上述場景中, multirelease.jar 可以在 Java 9 中使用, 不過 Helper 這個類使用的不是頂層的 multirelease.Helper 這個 class, 而是處在“META-INF/versions/9”下面的這個。這是特别為 Java 9 準備的 class 版本,可以運用 Java 9 所提供的特性和庫。同時,在早期的 Java 諸版本中使用這個 JAR 也是能運作的,因為較老版本的 Java 隻會看到頂層的這個 Helper 類。

10. 多分辨率圖像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

如你所見,Java 9 提供了一大堆或大或小的功能特性,你準備好了麼?

轉載整理自:

http://geek.csdn.net/news/detail/196632

https://www.oschina.net/translate/java-9-new-features?print

繼續閱讀