萬字總結(jié)Java 9~15新特性,真香!
別人家的特性都用了幾年了,我 Java 才出來,哈哈!真實(shí)!
Java9
發(fā)布于 2017 年 9 月 21 日 。作為 Java8 之后 3 年半才發(fā)布的新版本,Java 9 帶 來了很多重大的變化其中最重要的改動(dòng)是 Java 平臺(tái)模塊系統(tǒng)的引入,其他還有諸如集合、Stream 流
Java 平臺(tái)模塊系統(tǒng)
Java 平臺(tái)模塊系統(tǒng)是Jigsaw Project的一部分,把模塊化開發(fā)實(shí)踐引入到了 Java 平臺(tái)中,可以讓我們的代碼可重用性更好!
什么是模塊系統(tǒng)?官方的定義是:A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor.
簡(jiǎn)單來說,你可以將一個(gè)模塊看作是一組唯一命名、可重用的包、資源和模塊描述文件(module-info.java)。
任意一個(gè) jar 文件,只要加上一個(gè) 模塊描述文件(module-info.java),就可以升級(jí)為一個(gè)模塊。

在引入了模塊系統(tǒng)之后,JDK 被重新組織成 94 個(gè)模塊。Java 應(yīng)用可以通過新增的 jlink 工具,創(chuàng)建出只包含所依賴的 JDK 模塊的自定義運(yùn)行時(shí)鏡像。這樣可以極大的減少 Java 運(yùn)行時(shí)環(huán)境的大小。
我們可以通過 exports 關(guān)鍵詞精準(zhǔn)控制哪些類可以對(duì)外開放使用,哪些類只能內(nèi)部使用。
module?my.module?{
????//exports?公開指定包的所有公共成員
????exports?com.my.package.name;
}
module?my.module?{
?????//exports…to?限制訪問的成員范圍
????export?com.my.package.name?to?com.specific.package;
}
Java 9 模塊的重要特征是在其工件(artifact)的根目錄中包含了一個(gè)描述模塊的 module-info.java 文 件。工件的格式可以是傳統(tǒng)的 JAR 文件或是 Java 9 新增的 JMOD 文件。
想要深入了解 Java 9 的模塊化,參見:
- 《Project Jigsaw: Module System Quick-Start Guide》
- 《Java 9 Modules: part 1》
Jshell
jshell 是 Java 9 新增的一個(gè)實(shí)用工具。為 Java 提供了類似于 Python 的實(shí)時(shí)命令行交互工具。
在 Jshell 中可以直接輸入表達(dá)式并查看其執(zhí)行結(jié)果。

集合增強(qiáng)
增加 了 List.of()、Set.of()、Map.of() 和 Map.ofEntries()等工廠方法來創(chuàng)建不可變集合(這部分內(nèi)容有點(diǎn)參考 Guava 的味道)
List.of("Java",?"C++");
Set.of("Java",?"C++");
Map.of("Java",?1,?"C++",?2);
使用 of() 創(chuàng)建的集合為不可變集合,不能進(jìn)行添加、刪除、替換、 排序等操作,不然會(huì)報(bào) java.lang.UnsupportedOperationException 異常。
Collectors 中增加了新的方法 filtering() 和 flatMapping()。
Collectors 的 filtering() 方法類似于 Stream 類的 filter() 方法,都是用于過濾元素。
Java 8 為
Collectors類引入了groupingBy操作,用于根據(jù)特定的屬性將對(duì)象分組。
List<String>?list?=?List.of("x","www",?"yy",?"zz");
Map<Integer,?List<String>>?result?=?list.stream()
????????.collect(Collectors.groupingBy(String::length,
????????????????Collectors.filtering(s?->?!s.contains("z"),
????????????????????????Collectors.toList())));
System.out.println(result);?//?{1=[x],?2=[yy],?3=[www]}
Stream & Optional 增強(qiáng)
Stream 中增加了新的方法 ofNullable()、dropWhile()、takeWhile() 以及 iterate() 方法的重載方法。
Java 9 中的 ofNullable() 方 法允許我們創(chuàng)建一個(gè)單元素的 Stream,可以包含一個(gè)非空元素,也可以創(chuàng)建一個(gè)空 Stream。而在 Java 8 中則不可以創(chuàng)建空的 Stream 。
Stream<String>?stringStream?=?Stream.ofNullable("Java");
System.out.println(stringStream.count());//?1
Stream<String>?nullStream?=?Stream.ofNullable(null);
System.out.println(nullStream.count());//0
takeWhile() 方法可以從 Stream 中依次獲取滿足條件的元素,直到不滿足條件為止結(jié)束獲取。
List<Integer>?integerList?=?List.of(11,?33,?66,?8,?9,?13);
integerList.stream().takeWhile(x?->?x?<?50).forEach(System.out::println);//?11?33
dropWhile() 方法的效果和 takeWhile() 相反。
List<Integer>?integerList2?=?List.of(11,?33,?66,?8,?9,?13);
integerList2.stream().dropWhile(x?->?x?<?50).forEach(System.out::println);//?66?8?9?13
iterate() 方法的新重載方法提供了一個(gè) Predicate 參數(shù) (判斷條件)來決定什么時(shí)候結(jié)束迭代
public?static<T>?Stream<T>?iterate(final?T?seed,?final?UnaryOperator<T>?f)?{
}
//?新增加的重載方法
public?static<T>?Stream<T>?iterate(T?seed,?Predicate<??super?T>?hasNext,?UnaryOperator<T>?next)?{
}
兩者的使用對(duì)比如下,新的 iterate() 重載方法更加靈活一些。
//?使用原始?iterate()?方法輸出數(shù)字?1~10
Stream.iterate(1,?i?->?i?+?1).limit(10).forEach(System.out::println);
//?使用新的?iterate()?重載方法輸出數(shù)字?1~10
Stream.iterate(1,?i?->?i?<=?10,?i?->?i?+?1).forEach(System.out::println);
Optional 類中新增了 ifPresentOrElse()、or() 和 stream() 等方法
ifPresentOrElse() 方法接受兩個(gè)參數(shù) Consumer 和 Runnable ,如果 Optional 不為空調(diào)用 Consumer 參數(shù),為空則調(diào)用 Runnable 參數(shù)。
public?void?ifPresentOrElse(Consumer<??super?T>?action,?Runnable?emptyAction)
Optional<Object>?objectOptional?=?Optional.empty();
objectOptional.ifPresentOrElse(System.out::println,?()?->?System.out.println("Empty!!!"));//?Empty!!!
or() 方法接受一個(gè) Supplier 參數(shù) ,如果 Optional 為空則返回 Supplier 參數(shù)指定的 Optional 值。
public?Optional<T>?or(Supplier<??extends?Optional<??extends?T>>?supplier)
Optional<Object>?objectOptional?=?Optional.empty();
objectOptional.or(()?->?Optional.of("java")).ifPresent(System.out::println);//java
String 存儲(chǔ)結(jié)構(gòu)變更
JDK 8 及之前的版本,String 一直是用 char[] 存儲(chǔ)。在 Java 9 之后,String 的實(shí)現(xiàn)改用 byte[] 數(shù)組存儲(chǔ)字符串。
進(jìn)程 API
Java 9 增加了 ProcessHandle 接口,可以對(duì)原生進(jìn)程進(jìn)行管理,尤其適合于管理長(zhǎng)時(shí)間運(yùn)行的進(jìn)程。
System.out.println(ProcessHandle.current().pid());
System.out.println(ProcessHandle.current().info());

平臺(tái)日志 API 和服務(wù)
Java 9 允許為 JDK 和應(yīng)用配置同樣的日志實(shí)現(xiàn)。新增了 System.LoggerFinder 用來管理 JDK 使 用的日志記錄器實(shí)現(xiàn)。JVM 在運(yùn)行時(shí)只有一個(gè)系統(tǒng)范圍的 LoggerFinder 實(shí)例。
我們可以通過添加自己的 System.LoggerFinder 實(shí)現(xiàn)來讓 JDK 和應(yīng)用使用 SLF4J 等其他日志記錄框架。
反應(yīng)式流 ( Reactive Streams )
在 Java9 中的 java.util.concurrent.Flow 類中新增了反應(yīng)式流規(guī)范的核心接口 。
Flow 中包含了 Flow.Publisher、Flow.Subscriber、Flow.Subscription 和 Flow.Processor 等 4 個(gè)核心接口。Java 9 還提供了SubmissionPublisher 作為Flow.Publisher 的一個(gè)實(shí)現(xiàn)。
變量句柄
變量句柄是一個(gè)變量或一組變量的引用,包括靜態(tài)域,非靜態(tài)域,數(shù)組元素和堆外數(shù)據(jù)結(jié)構(gòu)中的組成部分等
變量句柄的含義類似于已有的方法句柄 MethodHandle ,由 Java 類 java.lang.invoke.VarHandle 來表示,可以使用類 java.lang.invoke.MethodHandles.Lookup 中的靜態(tài)工廠方法來創(chuàng)建 VarHandle 對(duì)象。
VarHandle 的出現(xiàn)替代了 java.util.concurrent.atomic 和 sun.misc.Unsafe 的部分操作。并且提供了一系列標(biāo)準(zhǔn)的內(nèi)存屏障操作,用于更加細(xì)粒度的控制內(nèi)存排序。在安全性、可用性、性能上都要優(yōu)于現(xiàn)有的 API。
改進(jìn)方法句柄(Method Handle)
方法句柄從 Java7 開始引入,Java9 在類java.lang.invoke.MethodHandles 中新增了更多的靜態(tài)方法來創(chuàng)建不同類型的方法句柄。
接口私有方法
Java 9 允許在接口中使用私有方法。
public?interface?MyInterface?{
????private?void?methodPrivate(){
????}
}
Java9 其它新特性
- try-with-resources 增強(qiáng) :在 try-with-resources 語句中可以使用 effectively-final 變量(什么是 effectively-final 變量,見這篇文章:《Effectively Final Variables in Java》
- 類
CompletableFuture中增加了幾個(gè)新的方法(completeAsync,orTimeout等) - Nashorn 引擎的增強(qiáng) :Nashorn 從 Java8 開始引入的 JavaScript 引擎,Java9 對(duì) Nashorn 做了些增強(qiáng),實(shí)現(xiàn)了一些 ES6 的新特性(Java 11 中已經(jīng)被棄用)。
- I/O 流的新特性 :增加了新的方法來讀取和復(fù)制
InputStream中包含的數(shù)據(jù) - 改進(jìn)應(yīng)用的安全性能 :Java 9 新增了 4 個(gè) SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 SHA3-512
- ......
Java10
發(fā)布于 2018 年 3 月 20 日,最知名的特性應(yīng)該是 var 關(guān)鍵字(局部變量類型推斷)的引入了,其他還有垃圾收集器改善、GC 改進(jìn)、性能提升、線程管控等一批新特性
var(局部變量推斷)
由于太多 Java 開發(fā)者希望 Java 中引入局部變量推斷,于是 Java 10 的時(shí)候它來了,也算是眾望所歸了!
Java 10 提供了 var 關(guān)鍵字聲明局部變量。
Scala 和 Kotlin 中有 val 關(guān)鍵字 (
final var組合關(guān)鍵字),Java10 中并沒有引入。
Java 10 只引入了 var,而
var?id?=?0;
var?codefx?=?new?URL("https://mp.weixin.qq.com/");
var?list?=?new?ArrayList<>();
var?list?=?List.of(1,?2,?3);
var?map?=?new?HashMap<String,?String>();
var?p?=?Paths.of("src/test/java/Java9FeaturesTest.java");
var?numbers?=?List.of("a",?"b",?"c");
for?(var?n?:?list)
????System.out.print(n+?"?");
var 關(guān)鍵字只能用于帶有構(gòu)造器的局部變量和 for 循環(huán)中。
var?count=null;?//?編譯不通過,不能聲明為?null
var?r?=?()?->?Math.random();//?編譯不通過,不能聲明為?Lambda表達(dá)式
var?array?=?{1,2,3};//?編譯不通過,不能聲明數(shù)組
var 并不會(huì)改變 Java 是一門靜態(tài)類型語言的事實(shí),編譯器負(fù)責(zé)推斷出類型。
相關(guān)閱讀:《Java 10 新特性之局部變量類型推斷》。
集合增強(qiáng)
list,set,map 提供了靜態(tài)方法copyOf()返回入?yún)⒓系囊粋€(gè)不可變拷貝。
以下為 JDK 的源碼:
static?<E>?List<E>?copyOf(Collection<??extends?E>?coll)?{
????return?ImmutableCollections.listCopy(coll);
}
使用 copyOf() 創(chuàng)建的集合為不可變集合,不能進(jìn)行添加、刪除、替換、 排序等操作,不然會(huì)報(bào) java.lang.UnsupportedOperationException 異常。IDEA 也會(huì)有相應(yīng)的提示。

java.util.stream.Collectors 中新增了靜態(tài)方法,用于將流中的元素收集為不可變的集合。
var?list?=?new?ArrayList<>();
list.stream().collect(Collectors.toUnmodifiableList());
list.stream().collect(Collectors.toUnmodifiableSet());
Optional
新增了orElseThrow()方法來在沒有值時(shí)拋出指定的異常。
Optional.ofNullable(cache.getIfPresent(key))
????????.orElseThrow(()?->?new?PrestoException(NOT_FOUND,?"Missing?entry?found?for?key:?"?+?key));
并行全垃圾回收器 G1
從 Java9 開始 G1 就了默認(rèn)的垃圾回收器,G1 是以一種低延時(shí)的垃圾回收器來設(shè)計(jì)的,旨在避免進(jìn)行 Full GC,但是 Java9 的 G1 的 FullGC 依然是使用單線程去完成標(biāo)記清除算法,這可能會(huì)導(dǎo)致垃圾回收期在無法回收內(nèi)存的時(shí)候觸發(fā) Full GC。
為了最大限度地減少 Full GC 造成的應(yīng)用停頓的影響,從 Java10 開始,G1 的 FullGC 改為并行的標(biāo)記清除算法,同時(shí)會(huì)使用與年輕代回收和混合回收相同的并行工作線程數(shù)量,從而減少了 Full GC 的發(fā)生,以帶來更好的性能提升、更大的吞吐量。
應(yīng)用程序類數(shù)據(jù)共享(擴(kuò)展 CDS 功能)
在 Java 5 中就已經(jīng)引入了類數(shù)據(jù)共享機(jī)制 (Class Data Sharing,簡(jiǎn)稱 CDS),允許將一組類預(yù)處理為共享歸檔文件,以便在運(yùn)行時(shí)能夠進(jìn)行內(nèi)存映射以減少 Java 程序的啟動(dòng)時(shí)間,當(dāng)多個(gè) Java 虛擬機(jī)(JVM)共享相同的歸檔文件時(shí),還可以減少動(dòng)態(tài)內(nèi)存的占用量,同時(shí)減少多個(gè)虛擬機(jī)在同一個(gè)物理或虛擬的機(jī)器上運(yùn)行時(shí)的資源占用。CDS 在當(dāng)時(shí)還是 Oracle JDK 的商業(yè)特性。
Java 10 在現(xiàn)有的 CDS 功能基礎(chǔ)上再次拓展,以允許應(yīng)用類放置在共享存檔中。CDS 特性在原來的 bootstrap 類基礎(chǔ)之上,擴(kuò)展加入了應(yīng)用類的 CDS 為 (Application Class-Data Sharing,AppCDS) 支持,大大加大了 CDS 的適用范圍。其原理為:在啟動(dòng)時(shí)記錄加載類的過程,寫入到文本文件中,再次啟動(dòng)時(shí)直接讀取此啟動(dòng)文本并加載。設(shè)想如果應(yīng)用環(huán)境沒有大的變化,啟動(dòng)速度就會(huì)得到提升。
Java10 其他新特性
- 線程-局部管控:Java 10 中線程管控引入 JVM 安全點(diǎn)的概念,將允許在不運(yùn)行全局 JVM 安全點(diǎn)的情況下實(shí)現(xiàn)線程回調(diào),由線程本身或者 JVM 線程來執(zhí)行,同時(shí)保持線程處于阻塞狀態(tài),這種方式使得停止單個(gè)線程變成可能,而不是只能啟用或停止所有線程
- 備用存儲(chǔ)裝置上的堆分配:Java 10 中將使得 JVM 能夠使用適用于不同類型的存儲(chǔ)機(jī)制的堆,在可選內(nèi)存設(shè)備上進(jìn)行堆內(nèi)存分配
- 統(tǒng)一的垃圾回收接口:Java 10 中,hotspot/gc 代碼實(shí)現(xiàn)方面,引入一個(gè)干凈的 GC 接口,改進(jìn)不同 GC 源代碼的隔離性,多個(gè) GC 之間共享的實(shí)現(xiàn)細(xì)節(jié)代碼應(yīng)該存在于輔助類中。統(tǒng)一垃圾回收接口的主要原因是:讓垃圾回收器(GC)這部分代碼更加整潔,便于新人上手開發(fā),便于后續(xù)排查相關(guān)問題。
- ......
Java11
Java11 于 2018 年 9 月 25 日正式發(fā)布,這是很重要的一個(gè)版本!Java 11 和 2017 年 9 月份發(fā)布的 Java 9 以及 2018 年 3 月份發(fā)布的 Java 10 相比,其最大的區(qū)別就是:在長(zhǎng)期支持(Long-Term-Support)方面,Oracle 表示會(huì)對(duì) Java 11 提供大力支持,這一支持將會(huì)持續(xù)至 2026 年 9 月。這是據(jù) Java 8 以后支持的首個(gè)長(zhǎng)期版本。

String
Java 11 增加了一系列的字符串處理方法,如以下所示。
Guide:說白點(diǎn)就是多了層封裝,JDK 開發(fā)組的人沒少看市面上常見的工具類框架啊!
//判斷字符串是否為空
"?".isBlank();//true
//去除字符串首尾空格
"?Java?".strip();//?"Java"
//去除字符串首部空格
"?Java?".stripLeading();???//?"Java?"
//去除字符串尾部空格
"?Java?".stripTrailing();??//?"?Java"
//重復(fù)字符串多少次
"Java".repeat(3);?????????????//?"JavaJavaJava"
//返回由行終止符分隔的字符串集合。
"A\nB\nC".lines().count();????//?3
"A\nB\nC".lines().collect(Collectors.toList());
Optional
新增了empty()方法來判斷指定的 Optional 對(duì)象是否為空。
var?op?=?Optional.empty();
System.out.println(op.isEmpty());//判斷指定的?Optional?對(duì)象是否為空
ZGC(可伸縮低延遲垃圾收集器)
ZGC 即 Z Garbage Collector,是一個(gè)可伸縮的、低延遲的垃圾收集器。
ZGC 主要為了滿足如下目標(biāo)進(jìn)行設(shè)計(jì):
- GC 停頓時(shí)間不超過 10ms
- 即能處理幾百 MB 的小堆,也能處理幾個(gè) TB 的大堆
- 應(yīng)用吞吐能力不會(huì)下降超過 15%(與 G1 回收算法相比)
- 方便在此基礎(chǔ)上引入新的 GC 特性和利用 colored 針以及 Load barriers 優(yōu)化奠定基礎(chǔ)
- 當(dāng)前只支持 Linux/x64 位平臺(tái)
ZGC 目前 處在實(shí)驗(yàn)階段,只支持 Linux/x64 平臺(tái)。
與 CMS 中的 ParNew 和 G1 類似,ZGC 也采用標(biāo)記-復(fù)制算法,不過 ZGC 對(duì)該算法做了重大改進(jìn)。
在 ZGC 中出現(xiàn) Stop The World 的情況會(huì)更少!
詳情可以看 :《新一代垃圾回收器 ZGC 的探索與實(shí)踐》
標(biāo)準(zhǔn) HTTP Client 升級(jí)
Java 11 對(duì) Java 9 中引入并在 Java 10 中進(jìn)行了更新的 Http Client API 進(jìn)行了標(biāo)準(zhǔn)化,在前兩個(gè)版本中進(jìn)行孵化的同時(shí),Http Client 幾乎被完全重寫,并且現(xiàn)在完全支持異步非阻塞。
并且,Java11 中,Http Client 的包名由 jdk.incubator.http 改為java.net.http,該 API 通過 CompleteableFuture 提供非阻塞請(qǐng)求和響應(yīng)語義。使用起來也很簡(jiǎn)單,如下:
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);
var(Lambda 參數(shù)的局部變量語法)
從 Java 10 開始,便引入了局部變量類型推斷這一關(guān)鍵特性。類型推斷允許使用關(guān)鍵字 var 作為局部變量的類型而不是實(shí)際類型,編譯器根據(jù)分配給變量的值推斷出類型。
Java 10 中對(duì) var 關(guān)鍵字存在幾個(gè)限制
- 只能用于局部變量上
- 聲明時(shí)必須初始化
- 不能用作方法參數(shù)
- 不能在 Lambda 表達(dá)式中使用
Java11 開始允許開發(fā)者在 Lambda 表達(dá)式中使用 var 進(jìn)行參數(shù)聲明。
//?下面兩者是等價(jià)的
Consumer<String>?consumer?=?(var?i)?->?System.out.println(i);
Consumer<String>?consumer?=?(String?i)?->?System.out.println(i);
啟動(dòng)單文件源代碼程序
JEP 330:啟動(dòng)單文件源代碼程序(aunch Single-File Source-Code Programs) 可以讓我們運(yùn)行單一文件的 Java 源代碼。此功能允許使用 Java 解釋器直接執(zhí)行 Java 源代碼。源代碼在內(nèi)存中編譯,然后由解釋器執(zhí)行,不需要在磁盤上生成 .class 文件了。
唯一的約束在于所有相關(guān)的類必須定義在同一個(gè) Java 文件中。
對(duì)于 Java 初學(xué)者并希望嘗試簡(jiǎn)單程序的人特別有用,并且能和 jshell 一起使用
一定能程度上增強(qiáng)了使用 Java 來寫腳本程序的能力。
Java11 其他新特性
- 新的垃圾回收器 Epsilon :一個(gè)完全消極的 GC 實(shí)現(xiàn),分配有限的內(nèi)存資源,最大限度的降低內(nèi)存占用和內(nèi)存吞吐延遲時(shí)間
- 低開銷的 Heap Profiling :Java 11 中提供一種低開銷的 Java 堆分配采樣方法,能夠得到堆分配的 Java 對(duì)象信息,并且能夠通過 JVMTI 訪問堆信息
- TLS1.3 協(xié)議 :Java 11 中包含了傳輸層安全性(TLS)1.3 規(guī)范(RFC 8446)的實(shí)現(xiàn),替換了之前版本中包含的 TLS,包括 TLS 1.2,同時(shí)還改進(jìn)了其他 TLS 功能,例如 OCSP 裝訂擴(kuò)展(RFC 6066,RFC 6961),以及會(huì)話散列和擴(kuò)展主密鑰擴(kuò)展(RFC 7627),在安全性和性能方面也做了很多提升
- 飛行記錄器(Java Flight Recorder) :飛行記錄器之前是商業(yè)版 JDK 的一項(xiàng)分析工具,但在 Java 11 中,其代碼被包含到公開代碼庫(kù)中,這樣所有人都能使用該功能了。
- ......
Java12
String
Java 11 增加了兩個(gè)的字符串處理方法,如以下所示。
indent() 方法可以實(shí)現(xiàn)字符串縮進(jìn)。
String?text?=?"Java";
//?縮進(jìn)?4?格
text?=?text.indent(4);
System.out.println(text);
text?=?text.indent(-10);
System.out.println(text);
輸出:
?????Java
Java
transform() 方法可以用來轉(zhuǎn)變指定字符串。
String?result?=?"foo".transform(input?->?input?+?"?bar");
System.out.println(result);?//?foo?bar
文件比較
Java 12 添加了以下方法來比較兩個(gè)文件:
public?static?long?mismatch(Path?path,?Path?path2)?throws?IOException
mismatch() 方法用于比較兩個(gè)文件,并返回第一個(gè)不匹配字符的位置,如果文件相同則返回 -1L。
代碼示例(兩個(gè)文件內(nèi)容相同的情況):
Path?filePath1?=?Files.createTempFile("file1",?".txt");
Path?filePath2?=?Files.createTempFile("file2",?".txt");
Files.writeString(filePath1,?"Java?12?Article");
Files.writeString(filePath2,?"Java?12?Article");
long?mismatch?=?Files.mismatch(filePath1,?filePath2);
assertEquals(-1,?mismatch);
代碼示例(兩個(gè)文件內(nèi)容不相同的情況):
Path?filePath3?=?Files.createTempFile("file3",?".txt");
Path?filePath4?=?Files.createTempFile("file4",?".txt");
Files.writeString(filePath3,?"Java?12?Article");
Files.writeString(filePath4,?"Java?12?Tutorial");
long?mismatch?=?Files.mismatch(filePath3,?filePath4);
assertEquals(8,?mismatch);
數(shù)字格式化工具類
NumberFormat 新增了對(duì)復(fù)雜的數(shù)字進(jìn)行格式化的支持
NumberFormat?fmt?=?NumberFormat.getCompactNumberInstance(Locale.US,?NumberFormat.Style.SHORT);
String?result?=?fmt.format(1000);
?System.out.println(result);?//?輸出為 1K,計(jì)算工資是多少K更方便了。。。
Shenandoah GC
Redhat 主導(dǎo)開發(fā)的 Pauseless GC 實(shí)現(xiàn),主要目標(biāo)是 99.9% 的暫停小于 10ms,暫停與堆大小無關(guān)等
和 Java11 開源的 ZGC 相比(需要升級(jí)到 JDK11 才能使用),Shenandoah GC 有穩(wěn)定的 JDK8u 版本,在 Java8 占據(jù)主要市場(chǎng)份額的今天有更大的可落地性。
G1 收集器提升
Java12 為默認(rèn)的垃圾收集器 G1 帶來了兩項(xiàng)更新:
- 可中止的混合收集集合 :JEP344 的實(shí)現(xiàn),為了達(dá)到用戶提供的停頓時(shí)間目標(biāo),JEP 344 通過把要被回收的區(qū)域集(混合收集集合)拆分為強(qiáng)制和可選部分,使 G1 垃圾回收器能中止垃圾回收過程。G1 可以中止可選部分的回收以達(dá)到停頓時(shí)間目標(biāo)
- 及時(shí)返回未使用的已分配內(nèi)存 :JEP346 的實(shí)現(xiàn),增強(qiáng) G1 GC,以便在空閑時(shí)自動(dòng)將 Java 堆內(nèi)存返回給操作系統(tǒng)
預(yù)覽新特性
作為預(yù)覽特性加入,需要在javac編譯和java運(yùn)行時(shí)增加參數(shù)--enable-preview 。
增強(qiáng) Switch
傳統(tǒng)的 switch 語法存在容易漏寫 break 的問題,而且從代碼整潔性層面來看,多個(gè) break 本質(zhì)也是一種重復(fù)
Java12 增強(qiáng)了 swtich 表達(dá)式,使用類似 lambda 語法條件匹配成功后的執(zhí)行塊,不需要多寫 break 。
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 主要在類型強(qiáng)轉(zhuǎn)前探測(cè)對(duì)象的具體類型。
之前的版本中,我們需要顯示地對(duì)對(duì)象進(jìn)行類型轉(zhuǎn)換。
Object?obj?=?"我是字符串";
if(obj?instanceof?String){
???String?str?=?(String)?obj;
?System.out.println(str);
}
新版的 instanceof 可以在判斷是否屬于具體的類型同時(shí)完成轉(zhuǎn)換。
Object?obj?=?"我是字符串";
if(obj?instanceof?String?str){
?System.out.println(str);
}
Java13
增強(qiáng) ZGC(釋放未使用內(nèi)存)
在 Java 11 中是實(shí)驗(yàn)性的引入的 ZGC 在實(shí)際的使用中存在未能主動(dòng)將未使用的內(nèi)存釋放給操作系統(tǒng)的問題。
ZGC 堆由一組稱為 ZPages 的堆區(qū)域組成。在 GC 周期中清空 ZPages 區(qū)域時(shí),它們將被釋放并返回到頁面緩存 ZPageCache 中,此緩存中的 ZPages 按最近最少使用(LRU)的順序,并按照大小進(jìn)行組織。
在 Java 13 中,ZGC 將向操作系統(tǒng)返回被標(biāo)識(shí)為長(zhǎng)時(shí)間未使用的頁面,這樣它們將可以被其他進(jìn)程重用。
SocketAPI 重構(gòu)
Java Socket API 終于迎來了重大更新!
Java 13 將 Socket API 的底層進(jìn)行了重寫, NioSocketImpl 是對(duì) PlainSocketImpl 的直接替代,它使用 java.util.concurrent 包下的鎖而不是同步方法。如果要使用舊實(shí)現(xiàn),請(qǐng)使用 -Djdk.net.usePlainSocketImpl=true。
并且,在 Java 13 中是默認(rèn)使用新的 Socket 實(shí)現(xiàn)。
public?final?class?NioSocketImpl?extends?SocketImpl?implements?PlatformSocketImpl?{
}
FileSystems
FileSystems 類中添加了以下三種新方法,以便更容易地使用將文件內(nèi)容視為文件系統(tǒng)的文件系統(tǒng)提供程序:
newFileSystem(Path)newFileSystem(Path, Map<String, ?>)newFileSystem(Path, Map<String, ?>, ClassLoader)
動(dòng)態(tài) CDS 存檔
Java 13 中對(duì) Java 10 中引入的應(yīng)用程序類數(shù)據(jù)共享(AppCDS)進(jìn)行了進(jìn)一步的簡(jiǎn)化、改進(jìn)和擴(kuò)展,即:允許在 Java 應(yīng)用程序執(zhí)行結(jié)束時(shí)動(dòng)態(tài)進(jìn)行類歸檔,具體能夠被歸檔的類包括所有已被加載,但不屬于默認(rèn)基層 CDS 的應(yīng)用程序類和引用類庫(kù)中的類。
這提高了應(yīng)用程序類數(shù)據(jù)共享(AppCDS)的可用性。無需用戶進(jìn)行試運(yùn)行來為每個(gè)應(yīng)用程序創(chuàng)建類列表。
$?java?-XX:ArchiveClassesAtExit=my_app_cds.jsa?-cp?my_app.jar
$?java?-XX:SharedArchiveFile=my_app_cds.jsa?-cp?my_app.jar
預(yù)覽新特性
文本塊
解決 Java 定義多行字符串時(shí)只能通過換行轉(zhuǎn)義或者換行連接符來變通支持的問題,引入三重雙引號(hào)來定義多行文本。
Java 13 支持兩個(gè) """ 符號(hào)中間的任何內(nèi)容都會(huì)被解釋為字符串的一部分,包括換行符。
未支持文本塊之前的 HTML 寫法:
String?json?="{\n"?+
??????????????"???\"name\":\"mkyong\",\n"?+
??????????????"???\"age\":38\n"?+
??????????????"}\n";
支持文本塊之后的 HTML 寫法:
?String?json?=?"""
????????????????{
????????????????????"name":"mkyong",
????????????????????"age":38
????????????????}
????????????????""";
未支持文本塊之前的 SQL 寫法:
String?query?=?"SELECT?`EMP_ID`,?`LAST_NAME`?FROM?`EMPLOYEE_TB`\n"?+
???????????????"WHERE?`CITY`?=?'INDIANAPOLIS'\n"?+
???????????????"ORDER?BY?`EMP_ID`,?`LAST_NAME`;\n";
支持文本塊之后的 SQL 寫法:
String?query?=?"""
???????????????SELECT?`EMP_ID`,?`LAST_NAME`?FROM?`EMPLOYEE_TB`
???????????????WHERE?`CITY`?=?'INDIANAPOLIS'
???????????????ORDER?BY?`EMP_ID`,?`LAST_NAME`;
???????????????""";
另外,String 類新增加了 3 個(gè)新的方法來操作文本塊:
formatted(Object... args):它類似于String的format()方法。添加它是為了支持文本塊的格式設(shè)置。stripIndent():用于去除文本塊中每一行開頭和結(jié)尾的空格。translateEscapes():轉(zhuǎn)義序列如 “\\t” 轉(zhuǎn)換為 “\t”
由于文本塊是一項(xiàng)預(yù)覽功能,可以在未來版本中刪除,因此這些新方法被標(biāo)記為棄用。
@Deprecated(forRemoval=true,?since="13")
public?String?stripIndent()?{
}
@Deprecated(forRemoval=true,?since="13")
public?String?formatted(Object...?args)?{
}
@Deprecated(forRemoval=true,?since="13")
public?String?translateEscapes()?{
}
增強(qiáng) Switch(引入 yield 關(guān)鍵字到 Switch 中)
Switch 表達(dá)式中就多了一個(gè)關(guān)鍵字用于跳出 Switch 塊的關(guān)鍵字 yield,主要用于返回一個(gè)值
yield和 return 的區(qū)別在于:return 會(huì)直接跳出當(dāng)前循環(huán)或者方法,而 yield 只會(huì)跳出當(dāng)前 Switch 塊,同時(shí)在使用 yield 時(shí),需要有 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";
????????};
?}
Java14
空指針異常精準(zhǔn)提示
通過 JVM 參數(shù)中添加-XX:+ShowCodeDetailsInExceptionMessages,可以在空指針異常中獲取更為詳細(xì)的調(diào)用信息,更快的定位和解決問題。
a.b.c.i?=?99;?//?假設(shè)這段代碼會(huì)發(fā)生空指針
Java 14 之前:
Exception?in?thread?"main"?java.lang.NullPointerException
????at?NullPointerExample.main(NullPointerExample.java:5)
Java 14 之后:
?//?增加參數(shù)后提示的異常中很明確的告知了哪里為空導(dǎo)致
Exception?in?thread?"main"?java.lang.NullPointerException:
????????Cannot?read?field?'c'?because?'a.b'?is?null.
????at?Prog.main(Prog.java:5)
switch 的增強(qiáng)(轉(zhuǎn)正)
Java12 引入的 switch(預(yù)覽特性)在 Java14 變?yōu)檎桨姹荆恍枰黾訁?shù)來啟用,直接在 JDK14 中就能使用。
Java12 為 switch 表達(dá)式引入了類似 lambda 語法條件匹配成功后的執(zhí)行塊,不需要多寫 break ,Java13 提供了 yield 來在 block 中返回值。
String?result?=?switch?(day)?{
????????????case?"M",?"W",?"F"?->?"MWF";
????????????case?"T",?"TH",?"S"?->?"TTS";
????????????default?->?{
????????????????if(day.isEmpty())
????????????????????yield?"Please?insert?a?valid?day.";
????????????????else
????????????????????yield?"Looks?like?a?Sunday.";
????????????}
????????};
System.out.println(result);
預(yù)覽新特性
record 關(guān)鍵字
簡(jiǎn)化數(shù)據(jù)類的定義方式,使用 record 代替 class 定義的類,只需要聲明屬性,就可以在獲得屬性的訪問方法,以及 toString(),hashCode(), equals()方法
類似于使用 class 定義類,同時(shí)使用了 lombok 插件,并打上了@Getter,@ToString,@EqualsAndHashCode注解
/**
?*?這個(gè)類具有兩個(gè)特征
?*?1.?所有成員屬性都是final
?*?2.?全部方法由構(gòu)造方法,和兩個(gè)成員屬性訪問器組成(共三個(gè))
?*?那么這種類就很適合使用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聲明的類會(huì)自動(dòng)擁有上面類中的三個(gè)方法
?*?2.?在這基礎(chǔ)上還附贈(zèng)了equals(),hashCode()方法以及toString()方法
?*?3.?toString方法中包括所有成員屬性的字符串表示形式及其名稱
?*/
record?Rectangle(float?length,?float?width)?{?}
文本塊
Java14 中,文本塊依然是預(yù)覽特性,不過,其引入了兩個(gè)新的轉(zhuǎn)義字符:
\: 表示行尾,不引入換行符\s:表示單個(gè)空格
String?str?=?"凡心所向,素履所往,生如逆旅,一葦以航。";
String?str2?=?"""
????????凡心所向,素履所往,?\
????????生如逆旅,一葦以航。""";
System.out.println(str2);//?凡心所向,素履所往,?生如逆旅,一葦以航。
String?text?=?"""
????????java
????????c++\sphp
????????""";
System.out.println(text);
//輸出:
java
c++?php
instanceof 增強(qiáng)
依然是預(yù)覽特性 ,Java 12 新特性中介紹過。
Java14 其他特性
- 從 Java11 引入的 ZGC 作為繼 G1 過后的下一代 GC 算法,從支持 Linux 平臺(tái)到 Java14 開始支持 MacOS 和 Window(個(gè)人感覺是終于可以在日常開發(fā)工具中先體驗(yàn)下 ZGC 的效果了,雖然其實(shí) G1 也夠用)
- 移除了 CMS(Concurrent Mark Sweep) 垃圾收集器(功成而退)
- 新增了 jpackage 工具,標(biāo)配將應(yīng)用打成 jar 包外,還支持不同平臺(tái)的特性包,比如 linux 下的
deb和rpm,window 平臺(tái)下的msi和exe
Java15
CharSequence
CharSequence 接口添加了一個(gè)默認(rèn)方法 isEmpty() 來判斷字符序列為空,如果是則返回 true。
public?interface?CharSequence?{
??default?boolean?isEmpty()?{
??????return?this.length()?==?0;
??}
}
TreeMap
TreeMap 新引入了下面這些方法:
putIfAbsent()computeIfAbsent()computeIfPresent()compute()merge()
ZGC(轉(zhuǎn)正)
Java11 的時(shí)候 ,ZGC 還在試驗(yàn)階段。
當(dāng)時(shí),ZGC 的出現(xiàn)讓眾多 Java 開發(fā)者看到了垃圾回收器的另外一種可能,因此備受關(guān)注。
經(jīng)過多個(gè)版本的迭代,不斷的完善和修復(fù)問題,ZGC 在 Java 15 已經(jīng)可以正式使用了!
不過,默認(rèn)的垃圾回收器依然是 G1。你可以通過下面的參數(shù)啟動(dòng) ZGC:
$?java?-XX:+UseZGC?className
EdDSA(數(shù)字簽名算法)
新加入了一個(gè)安全性和性能都更強(qiáng)的基于 Edwards-Curve Digital Signature Algorithm (EdDSA)實(shí)現(xiàn)的數(shù)字簽名算法。
雖然其性能優(yōu)于現(xiàn)有的 ECDSA 實(shí)現(xiàn),不過,它并不會(huì)完全取代 JDK 中現(xiàn)有的橢圓曲線數(shù)字簽名算法( ECDSA)。
KeyPairGenerator?kpg?=?KeyPairGenerator.getInstance("Ed25519");
KeyPair?kp?=?kpg.generateKeyPair();
byte[]?msg?=?"test_string".getBytes(StandardCharsets.UTF_8);
Signature?sig?=?Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update(msg);
byte[]?s?=?sig.sign();
String?encodedString?=?Base64.getEncoder().encodeToString(s);
System.out.println(encodedString);
輸出:
0Hc0lxxASZNvS52WsvnncJOH/mlFhnA8Tc6D/k5DtAX5BSsNVjtPF4R4+yMWXVjrvB2mxVXmChIbki6goFBgAg==
文本塊(轉(zhuǎn)正)
在 Java 15 ,文本塊是正式的功能特性了。
隱藏類(Hidden Classes)
隱藏類是為框架(frameworks)所設(shè)計(jì)的,隱藏類不能直接被其他類的字節(jié)碼使用,只能在運(yùn)行時(shí)生成類并通過反射間接使用它們。
預(yù)覽新特性
record 關(guān)鍵字
Java 15 對(duì) Java 14 中引入的預(yù)覽新特性進(jìn)行了增強(qiáng),主要是引入了一個(gè)新的概念 密封類(Sealed Classes)。
密封類可以對(duì)繼承或者實(shí)現(xiàn)它們的類進(jìn)行限制。
比如抽象類 Person 只允許 Employee 和 Manager 繼承。
public?abstract?sealed?class?Person
????permits?Employee,?Manager?{
????//...
}
另外,任何擴(kuò)展密封類的類本身都必須聲明為 sealed、non-sealed 或 final。
public?final?class?Employee?extends?Person?{
}
public?non-sealed?class?Manager?extends?Person?{
}

在 java.lang.Class 增加了兩個(gè)公共方法用于獲取 Record 類信息:
RecordComponent[] getRecordComponents()boolean isRecord()
instanceof 模式匹配
Java 15 并沒有對(duì)此特性進(jìn)行調(diào)整,繼續(xù)預(yù)覽特性,主要用于接受更多的使用反饋。
在未來的 Java 版本中,Java 的目標(biāo)是繼續(xù)完善 instanceof 模式匹配新特性。
Java15 其他新特性
- Nashorn JavaScript 引擎徹底移除 :Nashorn 從 Java8 開始引入的 JavaScript 引擎,Java9 對(duì) Nashorn 做了些增強(qiáng),實(shí)現(xiàn)了一些 ES6 的新特性。在 Java 11 中就已經(jīng)被棄用,到了 Java 15 就徹底被刪除了。
- DatagramSocket API 重構(gòu)
- 禁用和廢棄偏向鎖(Biased Locking) :偏向鎖的引入增加了 JVM 的復(fù)雜性大于其帶來的性能提升。不過,你仍然可以使用
-XX:+UseBiasedLocking啟用偏向鎖定,但它會(huì)提示 這是一個(gè)已棄用的 API。 - ......
總結(jié)
關(guān)于預(yù)覽特性
先貼一段 oracle 官網(wǎng)原文: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.
這是一個(gè)預(yù)覽功能,該功能的設(shè)計(jì),規(guī)格和實(shí)現(xiàn)是完整的,但不是永久性的,這意味著該功能可能以其他形式存在或在將來的 JDK 版本中根本不存在。要編譯和運(yùn)行包含預(yù)覽功能的代碼,必須指定其他命令行選項(xiàng)。
就以switch的增強(qiáng)為例子,從 Java12 中推出,到 Java13 中將繼續(xù)增強(qiáng),直到 Java14 才正式轉(zhuǎn)正進(jìn)入 JDK 可以放心使用,不用考慮后續(xù) JDK 版本對(duì)其的改動(dòng)或修改
一方面可以看出 JDK 作為標(biāo)準(zhǔn)平臺(tái)在增加新特性的嚴(yán)謹(jǐn)態(tài)度,另一方面?zhèn)€人認(rèn)為是對(duì)于預(yù)覽特性應(yīng)該采取審慎使用的態(tài)度。特性的設(shè)計(jì)和實(shí)現(xiàn)容易,但是其實(shí)際價(jià)值依然需要在使用中去驗(yàn)證
JVM 虛擬機(jī)優(yōu)化
每次 Java 版本的發(fā)布都伴隨著對(duì) JVM 虛擬機(jī)的優(yōu)化,包括對(duì)現(xiàn)有垃圾回收算法的改進(jìn),引入新的垃圾回收算法,移除老舊的不再適用于今天的垃圾回收算法等
整體優(yōu)化的方向是高效,低時(shí)延的垃圾回收表現(xiàn)
對(duì)于日常的應(yīng)用開發(fā)者可能比較關(guān)注新的語法特性,但是從一個(gè)公司角度來說,在考慮是否升級(jí) Java 平臺(tái)時(shí)更加考慮的是JVM 運(yùn)行時(shí)的提升
參考資料
- JDK Project Overview :<https://openjdk.java.net/projects/jdk/ >
- IBM Developer Java9 https://www.ibm.com/developerworks/cn/java/the-new-features-of-Java-9/
- Guide to Java10 https://www.baeldung.com/java-10-overview
- Java 10 新特性介紹https://www.ibm.com/developerworks/cn/java/the-new-features-of-Java-10/index.html
- IBM Devloper Java11 https://www.ibm.com/developerworks/cn/java/the-new-features-of-Java-11/index.html
- Java 11 – Features and Comparison:https://www.geeksforgeeks.org/java-11-features-and-comparison/
- Oracle Java12 ReleaseNote https://www.oracle.com/technetwork/java/javase/12all-relnotes-5211423.html#NewFeature
- Oracle Java13 ReleaseNote https://www.oracle.com/technetwork/java/javase/13all-relnotes-5461743.html#NewFeature
- New Features in Java 12 https://www.baeldung.com/java-12-new-features
- New Java13 Features https://www.baeldung.com/java-13-new-features
- Java13 新特性概述 https://www.ibm.com/developerworks/cn/java/the-new-features-of-Java-13/index.html
- Oracle Java14 record https://docs.oracle.com/en/java/javase/14/language/records.html
- java14-features https://www.techgeeknext.com/java/java14-features
- Java 14 Features : https://www.journaldev.com/37273/java-14-features
- What is new in Java 15: https://mkyong.com/java/what-is-new-in-java-15/
????萬字Java知識(shí)地圖助你成為Offer收割機(jī)
作者簡(jiǎn)介:
博主從華中科技大學(xué)碩士畢業(yè),是一個(gè)對(duì)技術(shù)有追求,對(duì)生活有激情的程序員。
幾年間浪跡于多個(gè)一線互聯(lián)網(wǎng)大廠,具有多年開發(fā)實(shí)戰(zhàn)經(jīng)驗(yàn)。如果你熱愛技術(shù)或者你也不滿足現(xiàn)狀喜歡搞事情,那你不妨關(guān)注我,讓我們一路同行,一起分享技術(shù)干貨、交流面試技巧,吐槽職場(chǎng)故事。
我有技術(shù)和故事,你來嗎?
小giegie 們,三連支持一下
