192
技術社區[雲棲]
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協議,並且替換了遺留的HTTPURLConnection
API。這些改變並不應該在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