你們好,我是Guide哥!這篇文章來自讀者的投稿,通過了兩次較大的改動,兩週的完善終於完成。Java 8新特性見這裏:Java8新特性最佳指南 。html
Guide 哥:別人家的特性都用了幾年了,我 Java 纔出來,哈哈!真實!java
發佈於 2017 年 9 月 21 日 。做爲 Java8 以後 3 年半才發佈的新版本,Java 9 帶 來了不少重大的變化其中最重要的改動是 Java 平臺模塊系統的引入,其餘還有諸如集合、Stream 流linux
Java 平臺模塊系統,也就是 Project Jigsaw,把模塊化開發實踐引入到了 Java 平臺中。在引入了模塊系統以後,JDK 被從新組織成 94 個模塊。Java 應用能夠經過新增的 jlink 工具,建立出只包含所依賴的 JDK 模塊的自定義運行時鏡像。這樣能夠極大的減小 Java 運行時環境的大小。git
Java 9 模塊的重要特徵是在其工件(artifact)的根目錄中包含了一個描述模塊的 module-info.class 文 件。 工件的格式能夠是傳統的 JAR 文件或是 Java 9 新增的 JMOD 文件。github
jshell 是 Java 9 新增的一個實用工具。爲 Java 提供了相似於 Python 的實時命令行交互工具。web
在 Jshell 中能夠直接輸入表達式並查看其執行結果算法
List.of()
、
Set.of()
、
Map.of()
和
Map.ofEntries()
等工廠方法來建立不可變集合,好比
List.of("Java", "C++");
、
Map.of("Java", 1, "C++", 2)
;(這部份內容有點參考 Guava 的味道)
Stream
中增長了新的方法
ofNullable
、
dropWhile
、
takeWhile
和
iterate
方法。
Collectors
中增長了新的方法
filtering
和
flatMapping
Optional
類中新增了
ifPresentOrElse
、
or
和
stream
等方法
Java 9 增長了 ProcessHandle
接口,能夠對原生進程進行管理,尤爲適合於管理長時間運行的進程shell
Java 9 容許爲 JDK 和應用配置一樣的日誌實現。新增了 System.LoggerFinder
用來管理 JDK 使 用的日誌記錄器實現。JVM 在運行時只有一個系統範圍的 LoggerFinder
實例。json
咱們能夠經過添加本身的 System.LoggerFinder
實現來讓 JDK 和應用使用 SLF4J 等其餘日誌記錄框架。bootstrap
java.util.concurrent.Flow
類中新增了反應式流規範的核心接口
Flow.Publisher
、
Flow.Subscriber
、
Flow.Subscription
和
Flow.Processor
等 4 個核心接口。Java 9 還提供了
SubmissionPublisher
做爲
Flow.Publisher
的一個實現。
MethodHandle
java.lang.invoke.VarHandle
來表示,可使用類
java.lang.invoke.MethodHandles.Lookup
中的靜態工廠方法來建立
VarHandle
對 象
java.lang.invoke.MethodHandles
中新增了更多的靜態方法來建立不一樣類型的方法句柄
CompletableFuture
中增長了幾個新的方法(completeAsync
,orTimeout
等)
發佈於 2018 年 3 月 20 日,最知名的特性應該是 var 關鍵字(局部變量類型推斷)的引入了,其餘還有垃圾收集器改善、GC 改進、性能提高、線程管控等一批新特性
var list = new ArrayList<String>(); // ArrayList<String>
Guide 哥:實際上 Lombok 早就體用了一個相似的關鍵字,使用它能夠簡化代碼,可是可能會下降程序的易讀性、可維護性。通常狀況下,我我的都不太推薦使用。
list,set,map 提供了靜態方法copyOf()
返回入參集合的一個不可變拷貝(如下爲 JDK 的源碼)
static <E> List<E> copyOf(Collection<? extends E> coll) {
return ImmutableCollections.listCopy(coll);
}
複製代碼
java.util.stream.Collectors
中新增了靜態方法,用於將流中的元素收集爲不可變的集合
orElseThrow()
方法來在沒有值時拋出異常
從 Java9 開始 G1 就了默認的垃圾回收器,G1 是以一種低延時的垃圾回收器來設計的,旨在避免進行 Full GC,可是 Java9 的 G1 的 FullGC 依然是使用單線程去完成標記清除算法,這可能會致使垃圾回收期在沒法回收內存的時候觸發 Full GC。
爲了最大限度地減小 Full GC 形成的應用停頓的影響,從 Java10 開始,G1 的 FullGC 改成並行的標記清除算法,同時會使用與年輕代回收和混合回收相同的並行工做線程數量,從而減小了 Full GC 的發生,以帶來更好的性能提高、更大的吞吐量。
在 Java 5 中就已經引入了類數據共享機制 (Class Data Sharing,簡稱 CDS),容許將一組類預處理爲共享歸檔文件,以便在運行時可以進行內存映射以減小 Java 程序的啓動時間,當多個 Java 虛擬機(JVM)共享相同的歸檔文件時,還能夠減小動態內存的佔用量,同時減小多個虛擬機在同一個物理或虛擬的機器上運行時的資源佔用
Java 10 在現有的 CDS 功能基礎上再次拓展,以容許應用類放置在共享存檔中。CDS 特性在原來的 bootstrap 類基礎之上,擴展加入了應用類的 CDS (Application Class-Data Sharing) 支持。其原理爲:在啓動時記錄加載類的過程,寫入到文本文件中,再次啓動時直接讀取此啓動文本並加載。設想若是應用環境沒有大的變化,啓動速度就會獲得提高
線程-局部管控:Java 10 中線程管控引入 JVM 安全點的概念,將容許在不運行全局 JVM 安全點的狀況下實現線程回調,由線程自己或者 JVM 線程來執行,同時保持線程處於阻塞狀態,這種方式使得中止單個線程變成可能,而不是隻能啓用或中止全部線程
備用存儲裝置上的堆分配:Java 10 中將使得 JVM 可以使用適用於不一樣類型的存儲機制的堆,在可選內存設備上進行堆內存分配
統一的垃圾回收接口:Java 10 中,hotspot/gc 代碼實現方面,引入一個乾淨的 GC 接口,改進不一樣 GC 源代碼的隔離性,多個 GC 之間共享的實現細節代碼應該存在於輔助類中。統一垃圾回收接口的主要緣由是:讓垃圾回收器(GC)這部分代碼更加整潔,便於新人上手開發,便於後續排查相關問題。
Java11 於 2018 年 9 月 25 日正式發佈,這是很重要的一個版本!Java 11 和 2017 年 9 月份發佈的 Java 9 以及 2018 年 3 月份發佈的 Java 10 相比,其最大的區別就是:在長期支持(Long-Term-Support)方面,Oracle 表示會對 Java 11 提供大力支持,這一支持將會持續至 2026 年 9 月。這是據 Java 8 之後支持的首個長期版本。
Java 11 增長了一系列的字符串處理方法,如如下所示。
Guide 哥:說白點就是多了層封裝,JDK 開發組的人沒少看市面上常見的工具類框架啊!
//判斷字符串是否爲空
" ".isBlank();//true
//去除字符串首尾空格
" Java ".strip();// "Java"
//去除字符串首部空格
" Java ".stripLeading(); // "Java "
//去除字符串尾部空格
" Java ".stripTrailing(); // " Java"
//重複字符串多少次
"Java".repeat(3); // "JavaJavaJava"
//返回由行終止符分隔的字符串集合。
"A\nB\nC".lines().count(); // 3
"A\nB\nC".lines().collect(Collectors.toList());
複製代碼
ZGC 即 Z Garbage Collector,是一個可伸縮的、低延遲的垃圾收集器。
ZGC 主要爲了知足以下目標進行設計:
ZGC 目前 處在實驗階段,只支持 Linux/x64 平臺
Java 11 對 Java 9 中引入並在 Java 10 中進行了更新的 Http Client API 進行了標準化,在前兩個版本中進行孵化的同時,Http Client 幾乎被徹底重寫,而且如今徹底支持異步非阻塞。
而且,Java11 中,Http Client 的包名由 jdk.incubator.http
改成java.net.http
,該 API 經過 CompleteableFuture
提供非阻塞請求和響應語義。
使用起來也很簡單,以下:
var request = HttpRequest.newBuilder()
.uri(URI.create("https://javastack.cn"))
.GET()
.build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 異步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
複製代碼
傳統的 switch 語法存在容易漏寫 break 的問題,並且從代碼整潔性層面來看,多個 break 本質也是一種重複
Java12 提供了 swtich 表達式,使用相似 lambda 語法條件匹配成功後的執行塊,不須要多寫 break
做爲預覽特性加入,須要在javac
編譯和java
運行時增長參數--enable-preview
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
複製代碼
NumberFormat
新增了對複雜的數字進行格式化的支持
NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
String result = fmt.format(1000);
System.out.println(result); // 輸出爲 1K,計算工資是多少K更方便了。。。
複製代碼
Switch
表達式中就多了一個關鍵字用於跳出 Switch
塊的關鍵字 yield
,主要用於返回一個值
yield
和 return
的區別在於:return
會直接跳出當前循環或者方法,而 yield
只會跳出當前 Switch
塊,同時在使用 yield
時,須要有 default
條件
private static String descLanguage(String name) {
return switch (name) {
case "Java": yield "object-oriented, platform independent and secured";
case "Ruby": yield "a programmer's best friend";
default: yield name +" is a good language";
};
}
複製代碼
解決 Java 定義多行字符串時只能經過換行轉義或者換行鏈接符來變通支持的問題,引入三重雙引號來定義多行文本
兩個"""
中間的任何內容都會被解釋爲字符串的一部分,包括換行符
String json ="{\n" +
" \"name\":\"mkyong\",\n" +
" \"age\":38\n" +
"}\n"; // 未支持文本塊以前
複製代碼
String json = """
{
"name":"mkyong",
"age":38
}
""";
複製代碼
簡化數據類的定義方式,使用 record 代替 class 定義的類,只須要聲明屬性,就能夠在得到屬性的訪問方法,以及 toString,hashCode,equals 方法
相似於使用 Class 定義類,同時使用了 lomobok 插件,並打上了@Getter,@ToString,@EqualsAndHashCode
註解
做爲預覽特性引入
/**
* 這個類具備兩個特徵
* 1. 全部成員屬性都是final
* 2. 所有方法由構造方法,和兩個成員屬性訪問器組成(共三個)
* 那麼這種類就很適合使用record來聲明
*/
final class Rectangle implements Shape {
final double length;
final double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
double length() { return length; }
double width() { return width; }
}
/**
* 1. 使用record聲明的類會自動擁有上面類中的三個方法
* 2. 在這基礎上還附贈了equals(),hashCode()方法以及toString()方法
* 3. toString方法中包括全部成員屬性的字符串表示形式及其名稱
*/
record Rectangle(float length, float width) { }
複製代碼
經過 JVM 參數中添加-XX:+ShowCodeDetailsInExceptionMessages
,能夠在空指針異常中獲取更爲詳細的調用信息,更快的定位和解決問題
a.b.c.i = 99; // 假設這段代碼會發生空指針
複製代碼
Exception in thread "main" java.lang.NullPointerException:
Cannot read field 'c' because 'a.b' is null.
at Prog.main(Prog.java:5) // 增長參數後提示的異常中很明確的告知了哪裏爲空致使
複製代碼
->
來替代之前的
:
+
break
;另外就是提供了 yield 來在 block 中返回值
Before Java 14
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
複製代碼
Java 14 enhancements
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
複製代碼
instanceof 主要在類型強轉前探測對象的具體類型,而後執行具體的強轉
新版的 instanceof 能夠在判斷的是否屬於具體的類型同時完成轉換
Object obj = "我是字符串";
if(obj instanceof String str){
System.out.println(str);
}
複製代碼
deb
和
rpm
,window 平臺下的
msi
和
exe
This is a preview feature, which is a feature whose design, specification, and implementation are complete, but is not permanent, which means that the feature may exist in a different form or not at all in future JDK releases. To compile and run code that contains preview features, you must specify additional command-line options.
switch
的加強爲例子,從 Java12 中推出,到 Java13 中將繼續加強,直到 Java14 才正式轉正進入 JDK 能夠放心使用,不用考慮後續 JDK 版本對其的改動或修改
本文使用 mdnice 排版