1. Java平臺級模塊系統
該特性使Java9最大的一個特性,Java提供該功能的主要的動機在于,減少內存的開銷,JVM啟動的時候,至少會有30~60MB的內存加載,主要原因是JVM需要加載rt.jar,不管其中的類是否被classloader加載,第一步整個jar都會被JVM加載到內存當中去,模塊化可以根據模塊的需要加載程序運行需要的class,那么JVM是如何知道需要加載哪些class的呢。具體請參考:【JDK9-模塊化系統】
2. Linking
當你使用具有顯式依賴關系的模塊和模塊化的JDK時,新的可能性出現了。你的應用程序模塊現在講聲明其對其他應用程序模塊的依賴以及對其所使用的JDK模塊的依賴。為什么不實用這些信息創建一個最小的運行時環境,其中只包含運行應用程序所需的那些模塊呢?這可以通過Java9中的新的jlink工具實現。你可以創建針對應用程序進行優化的最小運行時映像而不需要使用完全加載JDK按照版本。
3. JShell:交互式Java REPL
許多語言已經具有交互式編程環境,Java現在加入了,可以從控制臺啟動jshell,并直接啟動輸入和執行Java代碼。
交互式shell還可以提供良好的學習環境以及提高生產力。
4. 改進的Javadoc
Javadoc現在支持在API文檔中的進行搜索,另外Javadoc的輸出現在符合兼容HTML5標準,此外每個Javadoc頁面都包含有關JDK模塊類或接口來源的信息。
實例,對Welcome類生成javadoc文檔:
5. 集合工廠方法
通常,希望在代碼中創建一個集合(如:List,Set等),并直接用一些元素填充它。實例化集合,幾個“add”調用,使得代碼重復,Java9添加了幾種集合工廠方法:
package com.jdk9.m;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class TestFactoryMethods {
public static void main(String[] args) {
Set set = Set.of(1, 2, 3);
Set mySet = new HashSet(set);
mySet.add(4);
System.out.println(mySet);
System.out.println(set.getClass() + ", " + set);
List list = List.of("a", "b");
System.out.println(list.getClass() + ", " + list);
Map map = Map.of("k1", "v1", "k2", "v2");
System.out.println(map.getClass() + ", " + map);
}
}
運行截圖:
除了更短和更好閱讀之外,這些方法也可以避免你選擇特定的集合實現,事實上,從工廠方法返回已放入數個元素的集合實現是高度優化的,因為它們時不可變的:在創建后,繼續添加元素到這些集合會導致“UnsupportedOperationException”。
6. 改進的Stream API
Java9中,Stream接口中添加了4個新的方法:dropWhile,takeWhile,ofNullable。還有一個iterate方法的新重載方法,可以讓你提供一個Predicate來指定什么時候結束迭代:
package com.jdk9.m;
import java.util.stream.IntStream;
public class TestStream {
public static void main(String[] args) {
IntStream.iterate(1, i -> i < 100, i -> i + 1).forEach(System.out::println);
}
}
除了對Stream本身的擴展,OPtional和Stream之間的結合也得到了改進,可以通過OPtional的新方法stream將一個Optional對象轉換為一個Stream對象:
Stream s = Optional.of(1).stream();
7. 私有接口方法
Java8帶來了接口的默認方法,接口現在也可以包含行為,而不僅僅是方法簽名,但是如果在接口上幾個默認方法,代碼幾乎相同,通常將重構這些方法,調用一個可復用的私有方法,但默認方法不能是私有的。將復用代碼創建為一個默認方法不是一個解決方案。Java9可以向接口添加私有輔助方法來解決此問題:
package com.jdk9.m;
public interface TestPrivate {
void im();
default void m1() {
init();
}
default void m2() {
init();
}
private void init() {
System.out.println("Initializing");
}
}
如果使用默認方法開發API,那么私有接口方法可能有助于構建其實現。
8. HTTP/2
JDK9之前,JDK提供的HTTP訪問功能,幾乎都需要依賴HttpURLConnection,但是這個類大家在寫代碼的時候很少使用,我們一般都會選擇Apache的HttpClient,此處在Java9的版本中引入了一個新的HTTP相關模塊,里面提供了堆HTTP訪問很好的支持,不僅支持HTTP1.1而且還支持HTTP2,以及WebSocket,但是目前這個模塊還在孵化階段,因此這套API不能保證100%正確。
實例:
package com.jdk9.m;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import jdk.incubator.http.HttpClient;
import jdk.incubator.http.HttpRequest;
import jdk.incubator.http.HttpResponse;
public class TestHttpClient {
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).GET().build();
HttpResponse response = client.send(request, HttpResponse.BodyHandler.asString());
System.out.println(response.statusCode());
}
}
運行截圖:
注意:JDK9的Java工程默認只可以訪問java.base模塊里面的包,但是HttpClient類是在模塊jdk.incubator.httpclient里面,所以如果要訪問HttpClient必須要創建模塊化文件module-info.java并且在里面顯式聲明引入jdk.incubator.httpclient,否則無法訪問HttpClient
module com.jdk9.m {
requires jdk.incubator.httpclient;
}
9. 多版本兼容JAR
當一個新版本的Java出現的時候,你的庫用戶要花費數年時間才會切換到這個新的版本,這就意味著庫得去向后兼容你想要支持的最老的Java版本。這實際上意味著未來的很長一段時間,你都不能在庫中運行Java9鎖提供的新特性。多版本兼容JAR功能讓你創建僅在特定版本Java環境中運行庫程序時選擇使用的class版本。
實例:
multirelease.jar
├── META-INF
│ └── versions
│ └── 9
│ └── multirelease
│ └── Helper.class
├── multirelease
├── Helper.class
└── Main.class
multirelease.jar可以在Java9中使用,不過Helper這個類使用的不是頂層的multirelease.Helper這個class,而是處在META-INFO/version/9下面的類。這是特別為Java9準備的class版本,可以運行Java9所提供的特性和庫。同時,在早期的Java諸版本中使用這個JAR也是能運行的,因為較老版本的Java只會看到頂層的Helper類。