再見Java8!萬字總結(jié)Java 9~15新特性!真香
Java 8 新特性見這里:Java8 新特性最佳指南 。
你可以在 Archived OpenJDK General-Availability Releases 上下載自己需要的 JDK 版本!
官方的新特性說明文檔地址:https://openjdk.java.net/projects/jdk/ 。
Guide:別人家的特性都用了幾年了,我 Java 才出來,哈哈!真實!
Java9
發(fā)布于 2017 年 9 月 21 日 。作為 Java8 之后 3 年半才發(fā)布的新版本,Java 9 帶 來了很多重大的變化其中最重要的改動是 Java 平臺模塊系統(tǒng)的引入,其他還有諸如集合、Stream 流
Java 平臺模塊系統(tǒng)
Java 平臺模塊系統(tǒng)是Jigsaw Project的一部分,把模塊化開發(fā)實踐引入到了 Java 平臺中,可以讓我們的代碼可重用性更好!
什么是模塊系統(tǒng)?官方的定義是:A uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor.
簡單來說,你可以將一個模塊看作是一組唯一命名、可重用的包、資源和模塊描述文件(module-info.java)。
任意一個 jar 文件,只要加上一個 模塊描述文件(module-info.java),就可以升級為一個模塊。

在引入了模塊系統(tǒng)之后,JDK 被重新組織成 94 個模塊。Java 應用可以通過新增的 jlink 工具,創(chuàng)建出只包含所依賴的 JDK 模塊的自定義運行時鏡像。這樣可以極大的減少 Java 運行時環(huán)境的大小。
我們可以通過 exports 關(guān)鍵詞精準控制哪些類可以對外開放使用,哪些類只能內(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)的根目錄中包含了一個描述模塊的 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 新增的一個實用工具。為 Java 提供了類似于 Python 的實時命令行交互工具。
在 Jshell 中可以直接輸入表達式并查看其執(zhí)行結(jié)果。

集合增強
增加 了 List.of()、Set.of()、Map.of() 和 Map.ofEntries()等工廠方法來創(chuàng)建不可變集合(這部分內(nèi)容有點參考 Guava 的味道)
List.of("Java", "C++");
Set.of("Java", "C++");
Map.of("Java", 1, "C++", 2);
使用 of() 創(chuàng)建的集合為不可變集合,不能進行添加、刪除、替換、 排序等操作,不然會報 java.lang.UnsupportedOperationException 異常。
Collectors 中增加了新的方法 filtering() 和 flatMapping()。
Collectors 的 filtering() 方法類似于 Stream 類的 filter() 方法,都是用于過濾元素。
Java 8 為
Collectors類引入了groupingBy操作,用于根據(jù)特定的屬性將對象分組。
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 增強
Stream 中增加了新的方法 ofNullable()、dropWhile()、takeWhile() 以及 iterate() 方法的重載方法。
Java 9 中的 ofNullable() 方 法允許我們創(chuàng)建一個單元素的 Stream,可以包含一個非空元素,也可以創(chuàng)建一個空 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() 方法的新重載方法提供了一個 Predicate 參數(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) {
}
兩者的使用對比如下,新的 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() 方法接受兩個參數(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() 方法接受一個 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 存儲結(jié)構(gòu)變更
JDK 8 及之前的版本,String 一直是用 char[] 存儲。在 Java 9 之后,String 的實現(xiàn)改用 byte[] 數(shù)組存儲字符串。
進程 API
Java 9 增加了 ProcessHandle 接口,可以對原生進程進行管理,尤其適合于管理長時間運行的進程。
System.out.println(ProcessHandle.current().pid());
System.out.println(ProcessHandle.current().info());

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

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

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

在 java.lang.Class 增加了兩個公共方法用于獲取 Record 類信息:
RecordComponent[] getRecordComponents()boolean isRecord()
instanceof 模式匹配
Java 15 并沒有對此特性進行調(diào)整,繼續(xù)預覽特性,主要用于接受更多的使用反饋。
在未來的 Java 版本中,Java 的目標是繼續(xù)完善 instanceof 模式匹配新特性。
Java15 其他新特性
Nashorn JavaScript 引擎徹底移除 :Nashorn 從 Java8 開始引入的 JavaScript 引擎,Java9 對 Nashorn 做了些增強,實現(xiàn)了一些 ES6 的新特性。在 Java 11 中就已經(jīng)被棄用,到了 Java 15 就徹底被刪除了。 DatagramSocket API 重構(gòu) 禁用和廢棄偏向鎖(Biased Locking) :偏向鎖的引入增加了 JVM 的復雜性大于其帶來的性能提升。不過,你仍然可以使用 -XX:+UseBiasedLocking啟用偏向鎖定,但它會提示 這是一個已棄用的 API。......
總結(jié)
關(guān)于預覽特性
先貼一段 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.
這是一個預覽功能,該功能的設(shè)計,規(guī)格和實現(xiàn)是完整的,但不是永久性的,這意味著該功能可能以其他形式存在或在將來的 JDK 版本中根本不存在。要編譯和運行包含預覽功能的代碼,必須指定其他命令行選項。
就以switch的增強為例子,從 Java12 中推出,到 Java13 中將繼續(xù)增強,直到 Java14 才正式轉(zhuǎn)正進入 JDK 可以放心使用,不用考慮后續(xù) JDK 版本對其的改動或修改
一方面可以看出 JDK 作為標準平臺在增加新特性的嚴謹態(tài)度,另一方面?zhèn)€人認為是對于預覽特性應該采取審慎使用的態(tài)度。特性的設(shè)計和實現(xiàn)容易,但是其實際價值依然需要在使用中去驗證
JVM 虛擬機優(yōu)化
每次 Java 版本的發(fā)布都伴隨著對 JVM 虛擬機的優(yōu)化,包括對現(xiàn)有垃圾回收算法的改進,引入新的垃圾回收算法,移除老舊的不再適用于今天的垃圾回收算法等
整體優(yōu)化的方向是高效,低時延的垃圾回收表現(xiàn)
對于日常的應用開發(fā)者可能比較關(guān)注新的語法特性,但是從一個公司角度來說,在考慮是否升級 Java 平臺時更加考慮的是JVM 運行時的提升
參考資料
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/
我是 Guide哥,一個工作2年有余,接觸編程已經(jīng)6年有余的程序員。大三開源 JavaGuide,目前已經(jīng) 100k+ Star。未來幾年,希望持續(xù)完善 JavaGuide,爭取能夠幫助更多學習 Java 的小伙伴!共勉!凎!點擊即可了解我的個人經(jīng)歷。
歡迎點贊分享。咱們下期再會!
