換掉 Java 8 !Java 17&18 新特性真香
《Java 面試指北》來啦!這是一份教你如何更高效地準(zhǔn)備面試的小冊,涵蓋常見八股文(系統(tǒng)設(shè)計、常見框架、分布式、高并發(fā) ......)、優(yōu)質(zhì)面經(jīng)等內(nèi)容。
JavaGuide 在線閱讀網(wǎng)站:https://javaguide.cn/
你好呀,我是 Guide,今天來分享下 Java 17 和 Java 18 的一些新特性。
Java 8 到 Java 15 的新特性,你可以在?https://javaguide.cn/ (JavaGuide 在線閱讀網(wǎng)站)上找到。

Guide 這里也是真的建議有條件的小伙伴嘗試一波?Java 17!不要死守 Java 8 了!
Java 17

Java 17 在 2021 年 9 月 14 日正式發(fā)布,Java 17 是一個長期支持(LTS)版本,這次更新共帶來 14 個新功能。
OpenJDK Java 17 下載:https://jdk.java.net/archive/
OpenJDK Java 17 文檔:https://openjdk.java.net/projects/jdk/17/
| JEP | 描述 |
|---|---|
| JEP 306 | 恢復(fù)始終嚴(yán)格的浮點語義[1] |
| JEP 356 | 增強的偽隨機數(shù)生成器[2] |
| JEP 382 | 使用新的 macOS 渲染庫[3] |
| JEP 391 | 支持 macOS/AArch64 架構(gòu)[4] |
| JEP 398 | 刪除已啟用的 Applet API[5] |
| JEP 403 | 更強的封裝 JDK 內(nèi)部封裝[6] |
| JEP 406 | Switch 模式匹配(預(yù)覽)[7] |
| JEP 407 | 移除 RMI Activation[8] |
| JEP 409 | 密封類(Sealed Classes)[9] |
| JEP 410 | JEP 401:移除實驗性的 AOT 和 JIT 編譯器[10] |
| JEP 411 | 棄用 Security Manager[11] |
| JEP 412 | 外部函數(shù)和內(nèi)存 API(孵化器)[12] |
| JEP 414 | Vector API(第二孵化器)[13] |
| JEP 415 | 指定上下文的反序列化過濾器[14] |
JEP 306:恢復(fù)始終嚴(yán)格的浮點語義
既然是恢復(fù)嚴(yán)格的浮點語義,那么說明在某個時間點之前,是始終嚴(yán)格的浮點語義的。其實在 Java SE 1.2 之前,所有的浮點計算都是嚴(yán)格的,但是以當(dāng)初的情況來看,過于嚴(yán)格的浮點計算在當(dāng)初流行的 x86 架構(gòu)和 x87 浮點協(xié)議處理器上運行,需要大量的額外的指令開銷,所以在 Java SE 1.2 開始,需要手動使用關(guān)鍵字 strictfp(strict float point) 才能啟用嚴(yán)格的浮點計算。
但是在 2021 年的今天,硬件早已發(fā)生巨變,當(dāng)初的問題已經(jīng)不存在了,所以從 Java 17 開始,恢復(fù)了始終嚴(yán)格的浮點語義這一特性。
擴展:strictfp?是 Java 中的一個關(guān)鍵字,大多數(shù)人可能沒有注意過它,它可以用在類、接口或者方法上,被 strictfp 修飾的部分中的 float 和 double 表達式會進行嚴(yán)格浮點計算。
下面是一個示例,其中的 testStrictfp() 被 strictfp 修飾。
package?com.wdbyte;
public?class?Main?{
????public?static?void?main(String[]?args)?{
????????testStrictfp();
????}
????public?strictfp?static?void?testStrictfp()?{
????????float?aFloat?=?0.6666666666666666666f;
????????double?aDouble?=?0.88888888888888888d;
????????double?sum?=?aFloat?+?aDouble;
????????System.out.println("sum:?"?+?sum);
????}
}
JEP 356:增強的偽隨機數(shù)生成器
為偽隨機數(shù)生成器 RPNG(pseudorandom number generator)增加了新的接口類型和實現(xiàn),讓在代碼中使用各種 PRNG 算法變得容易許多。
這次增加了 RandomGenerator 接口,為所有的 PRNG 算法提供統(tǒng)一的 API,并且可以獲取不同類型的 PRNG 對象流。同時也提供了一個新類 RandomGeneratorFactory 用于構(gòu)造各種 RandomGenerator 實例,在 RandomGeneratorFactory 中使用 ServiceLoader.provider 來加載各種 PRNG 實現(xiàn)。
下面是一個使用示例:隨便選擇一個 PRNG 算法生成 5 個 10 以內(nèi)的隨機數(shù)。
package?com.wdbyte.java17;
import?java.util.Date;
import?java.util.random.RandomGenerator;
import?java.util.random.RandomGeneratorFactory;
import?java.util.stream.Stream;
/**
?*?@author?niulang
?*/
public?class?JEP356?{
????public?static?void?main(String[]?args)?{
????????RandomGeneratorFactory?l128X256MixRandom?=?RandomGeneratorFactory.of("L128X256MixRandom");
????????//?使用時間戳作為隨機數(shù)種子
????????RandomGenerator?randomGenerator?=?l128X256MixRandom.create(System.currentTimeMillis());
????????for?(int?i?=?0;?i?5;?i++)?{
????????????System.out.println(randomGenerator.nextInt(10));
????????}
????}
}
得到輸出:
7
3
4
4
6
你也可以遍歷出所有的 PRNG 算法。
RandomGeneratorFactory.all().forEach(factory?->?{
????System.out.println(factory.group()?+?":"?+?factory.name());
});
得到輸出:
LXM:L32X64MixRandom
LXM:L128X128MixRandom
LXM:L64X128MixRandom
Legacy:SecureRandom
LXM:L128X1024MixRandom
LXM:L64X128StarStarRandom
Xoshiro:Xoshiro256PlusPlus
LXM:L64X256MixRandom
Legacy:Random
Xoroshiro:Xoroshiro128PlusPlus
LXM:L128X256MixRandom
Legacy:SplittableRandom
LXM:L64X1024MixRandom
可以看到 Legacy:Random 也在其中,新的 API 兼容了老的 Random 方式,所以你也可以使用新的 API 調(diào)用 Random 類生成隨機數(shù)。
//?使用?Random
RandomGeneratorFactory?l128X256MixRandom?=?RandomGeneratorFactory.of("Random");
//?使用時間戳作為隨機數(shù)種子
RandomGenerator?randomGenerator?=?l128X256MixRandom.create(System.currentTimeMillis());
for?(int?i?=?0;?i?5;?i++)?{
????System.out.println(randomGenerator.nextInt(10));
}
擴展閱讀:增強的偽隨機數(shù)生成器[15]
JEP 382:使用新的 macOS 渲染庫
macOS 為了提高圖形的渲染性能,在 2018 年 9 月拋棄了之前的 OpenGL 渲染庫 ,而使用了 Apple Metal 進行代替。Java 17 這次更新開始支持 Apple Metal,不過對于 API 沒有任何改變,這一些都是內(nèi)部修改。
擴展閱讀:macOS Mojave 10.14 Release Notes[16],Apple Metal[17]
JEP 391:支持 macOS/AArch64 架構(gòu)
起因是 Apple 在 2020 年 6 月的 WWDC 演講中宣布,將開啟一項長期的將 Macintosh 計算機系列從 x64 過度到 AArch64 的長期計劃,因此需要盡快的讓 JDK 支持 macOS/AArch64 。
Linux 上的 AArch64 支持以及在 Java 16 時已經(jīng)支持,可以查看之前的文章了解。
擴展:Java 16 新功能介紹 - JEP 386[18]
JEP 398:刪除已棄用的 Applet API
Applet 是使用 Java 編寫的可以嵌入到 HTML 中的小應(yīng)用程序,嵌入方式是通過普通的 HTML 標(biāo)記語法,由于早已過時,幾乎沒有場景在使用了。
示例:嵌入 Hello.class
<applet?code="Hello.class"?height=200?width=200>applet>
Applet API 在 Java 9 時已經(jīng)標(biāo)記了廢棄,現(xiàn)在 Java 17 中將徹底刪除。
JEP 403:更強的 JDK 內(nèi)部封裝
如 Java 16 的 JEP 396 中描述的一樣,為了提高 JDK 的安全性,使 --illegal-access 選項的默認模式從允許更改為拒絕。通過此更改,JDK 的內(nèi)部包和 API(關(guān)鍵內(nèi)部 API[19] 除外)將不再默認打開。
但是在 Java 17 中,除了 sun.misc.Unsafe ,使用 --illegal-access 命令也不能打開 JDK 內(nèi)部的強封裝模式了,除了 sun.misc.Unsafe API .
在 Java 17 中使用 --illegal-access 選項將會得到一個命令已經(jīng)移除的警告。
???bin?./java?-version
openjdk?version?"17"?2021-09-14
OpenJDK?Runtime?Environment?(build?17+35-2724)
OpenJDK?64-Bit?Server?VM?(build?17+35-2724,?mixed?mode,?sharing)
???bin?./java?--illegal-access=warn
OpenJDK?64-Bit?Server?VM?warning:?Ignoring?option?--illegal-access=warn;?support?was?removed?in?17.0
擴展閱讀:JEP 403:更強的 JDK 內(nèi)部封裝[20],Java 16 新功能介紹[21]
JEP 406:switch 的類型匹配(預(yù)覽)
如 instanceof 一樣,為 switch 也增加了類型匹配自動轉(zhuǎn)換功能。
在之前,使用 instanceof 需要如下操作:
if?(obj?instanceof?String)?{
????String?s?=?(String)?obj;????//?grr...
????...
}
多余的類型強制轉(zhuǎn)換,而現(xiàn)在:
if?(obj?instanceof?String?s)?{
????//?Let?pattern?matching?do?the?work!
????...
}
switch 也可以使用類似的方式了。
static?String?formatterPatternSwitch(Object?o)?{
????return?switch?(o)?{
????????case?Integer?i?->?String.format("int?%d",?i);
????????case?Long?l????->?String.format("long?%d",?l);
????????case?Double?d??->?String.format("double?%f",?d);
????????case?String?s??->?String.format("String?%s",?s);
????????default????????->?o.toString();
????};
}
對于 null 值的判斷也有了新的方式。
//?Java?17?之前
static?void?testFooBar(String?s)?{
????if?(s?==?null)?{
????????System.out.println("oops!");
????????return;
????}
????switch?(s)?{
????????case?"Foo",?"Bar"?->?System.out.println("Great");
????????default???????????->?System.out.println("Ok");
????}
}
//?Java?17
static?void?testFooBar(String?s)?{
????switch?(s)?{
????????case?null?????????->?System.out.println("Oops");
????????case?"Foo",?"Bar"?->?System.out.println("Great");
????????default???????????->?System.out.println("Ok");
????}
}
擴展閱讀:JEP 406:switch 的類型匹配(預(yù)覽)[22]
JEP 407:移除 RMI Activation
移除了在 JEP 385 中被標(biāo)記廢除的 RMI(Remote Method Invocation)Activation,但是 RMI 其他部分不會受影響。
RMI Activation 在 Java 15 中的 JEP 385 已經(jīng)被標(biāo)記為過時廢棄,至今沒有收到不良反饋,因此決定在 Java 17 中正式移除。
擴展閱讀:JEP 407:移除 RMI Activation[23]
JEP 409:密封類(Sealed Classes)
Sealed Classes 在 Java 15 中的 JEP 360 中提出,在 Java 16 中的 JEP 397 再次預(yù)覽,現(xiàn)在 Java 17 中成為正式的功能,相比 Java 16 并沒有功能變化,這里不再重復(fù)介紹,想了解的可以參考之前文章。
擴展閱讀:Java 16 新功能介紹[24],JEP 409: Sealed Classes[25]
JEP 401:移除實驗性的 AOT 和 JIT 編譯器
在 Java 9 的 JEP 295 中,引入了實驗性的提前編譯 jaotc 工具,但是這個特性自從引入依賴用處都不太大,而且需要大量的維護工作,所以在 Java 17 中決定刪除這個特性。
主要移除了三個 JDK 模塊:
jdk.aot - jaotc 工具。 Jdk.internal.vm.compiler - Graal 編譯器。 jdk.internal.vm.compiler.management
同時也移除了部分與 AOT 編譯相關(guān)的 HotSpot 代碼:
src/hotspot/share/aot— dumps and loads AOT codeAdditional code guarded by #if INCLUDE_AOT
JEP 411:棄用 Security Manager
Security Manager 在 JDK 1.0 時就已經(jīng)引入,但是它一直都不是保護服務(wù)端以及客戶端 Java 代碼的主要手段,為了 Java 的繼續(xù)發(fā)展,決定棄用 Security Manager,在不久的未來進行刪除。
@Deprecated(since="17",?forRemoval=true)
public?class?SecurityManager?{
?//?...
}
JEP 412:外部函數(shù)和內(nèi)存 API (孵化)
新的 API 允許 Java 開發(fā)者與 JVM 之外的代碼和數(shù)據(jù)進行交互,通過調(diào)用外部函數(shù),可以在不使用 JNI 的情況下調(diào)用本地庫。
這是一個孵化功能;需要添加--add-modules jdk.incubator.foreign來編譯和運行 Java 代碼。
歷史
Java 14 JEP 370[26]引入了外部內(nèi)存訪問 API(孵化器)。 Java 15 JEP 383[27]引入了外部內(nèi)存訪問 API(第二孵化器)。 Java 16 JEP 389[28]引入了外部鏈接器 API(孵化器)。 Java 16 JEP 393[29]引入了外部內(nèi)存訪問 API(第三孵化器)。 Java 17 JEP 412[30]引入了外部函數(shù)和內(nèi)存 API(孵化器)。
擴展閱讀:JEP 412:外部函數(shù)和內(nèi)存 API (孵化)[31]
JEP 414:Vector API(二次孵化)
在 Java 16 中引入一個新的 API 來進行向量計算,它可以在運行時可靠的編譯為支持的 CPU 架構(gòu),從而實現(xiàn)更優(yōu)的計算能力。
現(xiàn)在 Java 17 中改進了 Vector API 性能,增強了例如對字符的操作、字節(jié)向量與布爾數(shù)組之間的相互轉(zhuǎn)換等功能。
JEP 415:指定上下文的反序列化過濾器
Java 中的序列化一直都是非常重要的功能,如果沒有序列化功能,Java 可能都不會占據(jù)開發(fā)語言的主導(dǎo)地位,序列化讓遠程處理變得容易和透明,同時也促進了 Java EE 的成功。
但是 Java 序列化的問題也很多,它幾乎會犯下所有的可以想象的錯誤,為開發(fā)者帶來持續(xù)的維護工作。但是要說明的是序列化的概念是沒有錯的,把對象轉(zhuǎn)換為可以在 JVM 之間自由傳輸,并且可以在另一端重新構(gòu)建的能力是完全合理的想法,問題在于 Java 中的序列化設(shè)計存在風(fēng)險,以至于爆出過很多和序列化相關(guān)的漏洞。
反序列化危險的一個原因是,有時候我們不好驗證將要進行反序列化的內(nèi)容是否存在風(fēng)險,而傳入的數(shù)據(jù)流可以自由引用對象,很有可能這個數(shù)據(jù)流就是攻擊者精心構(gòu)造的惡意代碼。
所以,JEP 415 允許在反序列化時,通過一個過濾配置,來告知本次反序列化允許或者禁止操作的類,反序列化時碰到被禁止的類,則會反序列化失敗。
反序列化示例
假設(shè) Dog 類中的 Poc 是惡意構(gòu)造的類,但是正常反序列化是可以成功的。
package?com.wdbyte.java17;
import?java.io.ByteArrayInputStream;
import?java.io.ByteArrayOutputStream;
import?java.io.IOException;
import?java.io.ObjectInputStream;
import?java.io.ObjectOutputStream;
import?java.io.Serializable;
/**
?*?@author?niulang
?*/
public?class?JEP415?{
????public?static?void?main(String[]?args)?throws?IOException,?ClassNotFoundException?{
????????Dog?dog?=?new?Dog("哈士奇");
????????dog.setPoc(new?Poc());
????????//?序列化?-?對象轉(zhuǎn)字節(jié)數(shù)組
????????ByteArrayOutputStream?byteArrayOutputStream?=?new?ByteArrayOutputStream();
????????try?(ObjectOutputStream?objectOutputStream?=?new?ObjectOutputStream(byteArrayOutputStream);)?{
????????????objectOutputStream.writeObject(dog);
????????}
????????byte[]?bytes?=?byteArrayOutputStream.toByteArray();
????????//?反序列化?-?字節(jié)數(shù)組轉(zhuǎn)對象
????????ByteArrayInputStream?byteArrayInputStream?=?new?ByteArrayInputStream(bytes);
????????ObjectInputStream?objectInputStream?=?new?ObjectInputStream(byteArrayInputStream);
????????Object?object?=?objectInputStream.readObject();
????????System.out.println(object.toString());
????}
}
class?Dog?implements?Serializable?{
????private?String?name;
????private?Poc?poc;
????public?Dog(String?name)?{
????????this.name?=?name;
????}
????@Override
????public?String?toString()?{
????????return?"Dog{"?+?"name='"?+?name?+?'\''?+?'}';
????}
??//?get...set...
}
class?Poc?implements?Serializable{
}
輸出結(jié)果:
Dog{name='哈士奇'}
反序列化過濾器
在 Java 17 中可以自定義反序列化過濾器,攔截不允許的類。
package?com.wdbyte.java17;
import?java.io.ByteArrayInputStream;
import?java.io.ByteArrayOutputStream;
import?java.io.IOException;
import?java.io.ObjectInputFilter;
import?java.io.ObjectInputStream;
import?java.io.ObjectOutputStream;
import?java.io.Serializable;
/**
?*?@author?niulang
?*/
public?class?JEP415?{
????public?static?void?main(String[]?args)?throws?IOException,?ClassNotFoundException?{
????????Dog?dog?=?new?Dog("哈士奇");
????????dog.setPoc(new?Poc());
????????//?序列化?-?對象轉(zhuǎn)字節(jié)數(shù)組
????????ByteArrayOutputStream?byteArrayOutputStream?=?new?ByteArrayOutputStream();
????????try?(ObjectOutputStream?objectOutputStream?=?new?ObjectOutputStream(byteArrayOutputStream);)?{
????????????objectOutputStream.writeObject(dog);
????????}
????????byte[]?bytes?=?byteArrayOutputStream.toByteArray();
????????//?反序列化?-?字節(jié)數(shù)組轉(zhuǎn)對象
????????ByteArrayInputStream?byteArrayInputStream?=?new?ByteArrayInputStream(bytes);
????????ObjectInputStream?objectInputStream?=?new?ObjectInputStream(byteArrayInputStream);
????????//?允許?com.wdbyte.java17.Dog?類,允許?java.base?中的所有類,拒絕其他任何類
????????ObjectInputFilter?filter?=?ObjectInputFilter.Config.createFilter(
????????????????????????"com.wdbyte.java17.Dog;java.base/*;!*");
????????objectInputStream.setObjectInputFilter(filter);
????????Object?object?=?objectInputStream.readObject();
????????System.out.println(object.toString());
????}
}
class?Dog?implements?Serializable?{
????private?String?name;
????private?Poc?poc;
????public?Dog(String?name)?{
????????this.name?=?name;
????}
????@Override
????public?String?toString()?{
????????return?"Dog{"?+?"name='"?+?name?+?'\''?+?'}';
????}
??//?get...set...
}
class?Poc?implements?Serializable{
}
這時反序列化會得到異常。
Exception?in?thread?"main"?java.io.InvalidClassException:?filter?status:?REJECTED
?at?java.base/java.io.ObjectInputStream.filterCheck(ObjectInputStream.java:1412)
?at?java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2053)
?at?java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1907)
?....
擴展閱讀:JEP 415:指定上下文的反序列化過濾器[32]
Java 18
Java 18 在 2022 年 3 月 22 日正式發(fā)布,這次更新共帶來 9 個新功能。
Java 18 不是一個長期支持版本,如果你想要升級自己的 JDK 版本的話,我會更推薦 Java17。目前來看,遷移到 Java17 的項目越來越多,尤其是在國外。
OpenJDK Java 18 下載:https://jdk.java.net/18/
OpenJDK Java 18 文檔:https://openjdk.java.net/projects/jdk/18/
| JEP | 描述 |
|---|---|
| JEP 400 | 默認為 UTF-8[33] |
| JEP 408 | 簡單的網(wǎng)絡(luò)服務(wù)器[34] |
| JEP 413 | Java API 文檔中的代碼片段[35] |
| JEP 416 | 使用方法句柄重新實現(xiàn)核心反射[36] |
| JEP 417 | Vector API(三次孵化)[37] |
| JEP 418 | 互聯(lián)網(wǎng)地址解析 SPI[38] |
| JEP 419 | Foreign Function & Memory API (二次孵化)[39] |
| JEP 420 | switch 模式匹配(二次預(yù)覽)[40] |
| JEP 421 | 棄用完成刪除[41] |
JEP 400:默認 UTF-8 字符編碼
JDK 一直都是支持 UTF-8 字符編碼,這次是把 UTF-8 設(shè)置為了默認編碼,也就是在不加任何指定的情況下,默認所有需要用到編碼的 JDK API 都使用 UTF-8 編碼,這樣就可以避免因為不同系統(tǒng),不同地區(qū),不同環(huán)境之間產(chǎn)生的編碼問題。
Mac OS 默認使用 UTF-8 作為默認編碼,但是其他操作系統(tǒng)上,編碼可能取決于系統(tǒng)的配置或者所在區(qū)域的設(shè)置。如中國大陸的 windows 使用 GBK 作為默認編碼。很多同學(xué)初學(xué) Java 時可能都遇到過一個正常編寫 Java 類,在 windows 系統(tǒng)的命令控制臺中運行卻出現(xiàn)亂碼的情況。
使用下面的命令可以輸出 JDK 的當(dāng)前編碼。
#?Mac?系統(tǒng),默認?UTF-8
???~?java?-XshowSettings:properties?-version?2>&1?|?grep?file.encoding
????file.encoding?=?UTF-8
????file.encoding.pkg?=?sun.io
???~
下面編寫一個簡單的 Java 程序,輸出默認字符編碼,然后輸出中文漢字 ”你好“,看看 Java 18 和 Java 17 運行區(qū)別。
系統(tǒng)環(huán)境:Windows 11
import?java.nio.charset.Charset;
public?class?Hello{
????public?static?void?main(String[]?args)?{
????????System.out.println(Charset.defaultCharset());????????System.out.println("你好");????}
}
從下面的運行結(jié)果中可以看到,使用 JDK 17 運行輸出的默認字符編碼是 GBK,輸出的中文 ”你好“ 已經(jīng)亂碼了;亂碼是因為 VsCode 默認的文本編輯器編碼是 UTF-8,而中國地區(qū)的 Windows 11 默認字符編碼是 GBK,也是 JDK 17 默認獲取到的編碼,所以會在控制臺輸出時亂碼;而使用 JDK 18 輸出的默認編碼就是 UTF-8,所以可以正常的輸出中文 ”你好“。

JEP 408:簡單的 Web 服務(wù)器
在 Java 18 中,提供了一個新命令 jwebserver,運行這個命令可以啟動一個簡單的 、最小化的靜態(tài) Web 服務(wù)器,它不支持 CGI 和 Servlet,所以最好的使用場景是用來測試、教育、演示等需求。
其實在如 Python、Ruby、PHP、Erlang 等許多平臺都提供了開箱即用的 Web 服務(wù)器,可見一個簡單的 Web 服務(wù)器是一個常見的需求,Java 一直沒有這方面的支持,現(xiàn)在可以了。
在 Java 18 中,使用 jwebserver 啟動一個 Web 服務(wù)器,默認發(fā)布的是當(dāng)前目錄。
在當(dāng)前目錄創(chuàng)建一個網(wǎng)頁文件 index.html
<html>
<head>
<meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>
head>
<body>
<h1>標(biāo)題h1>
body>
html>
啟動 jwebserver.
???bin?./jwebserver
Binding?to?loopback?by?default.?For?all?interfaces?use?"-b?0.0.0.0"?or?"-b?::".
Serving?/Users/darcy/develop/jdk-18.jdk/Contents/Home/bin?and?subdirectories?on?127.0.0.1?port?8000
URL?http://127.0.0.1:8000/
瀏覽器訪問:

有請求時會在控制臺輸出請求信息:
127.0.0.1?-?-?[26/3月/2022:16:53:30?+0800]?"GET?/favicon.ico?HTTP/1.1"?404?-
127.0.0.1?-?-?[26/3月/2022:16:55:13?+0800]?"GET?/?HTTP/1.1"?200?-
通過 help 參數(shù)可以查看 jwebserver 支持的參數(shù)。
???bin?./jwebserver?--help
Usage:?jwebserver?[-b?bind?address]?[-p?port]?[-d?directory]
??????????????????[-o?none|info|verbose]?[-h?to?show?options]
??????????????????[-version?to?show?version?information]
Options:
-b,?--bind-address????-?綁定地址.?Default:?127.0.0.1?(loopback).
????????????????????????For?all?interfaces?use?"-b?0.0.0.0"?or?"-b?::".
-d,?--directory???????-?指定目錄.?Default:?current?directory.
-o,?--output??????????-?Output?format.?none|info|verbose.?Default:?info.
-p,?--port????????????-?綁定端口.?Default:?8000.
-h,?-?,?--help????????-?Prints?this?help?message?and?exits.
-version,?--version???-?Prints?version?information?and?exits.
To?stop?the?server,?press?Ctrl?+?C.
JEP 413:Javadoc 中支持代碼片段
在 Java 18 之前,已經(jīng)支持在 Javadoc 中引入代碼片段,這樣可以在某些場景下更好的展示描述信息,但是之前的支持功能有限,比如我想高亮代碼片段中的某一段代碼是無能為力的。現(xiàn)在 Java 18 優(yōu)化了這個問題,增加了 @snippet 來引入更高級的代碼片段。
在 Java 18 之前,使用 來引入代碼片段。{@code ...}
?/**
??*?時間工具類
??* Java 18 之前引入代碼片段:
??*?{@code
??*?????public?static?String?timeStamp()?{
??*????????long?time?=?System.currentTimeMillis();
??*?????????return?String.valueOf(time?/?1000);
??*?????}
??*?}
??*
??*/
生成 Javadoc 之后,效果如下:

高亮代碼片段
從 Java 18 開始,可以使用 @snippet 來生成注釋,且可以高亮某個代碼片段。
/**
?*?在?Java?18?之后可以使用新的方式
?*?下面的代碼演示如何使用?{@code?Optional.isPresent}:
?*?{@snippet?:
?*?if?(v.isPresent())?{
?*?????System.out.println("v:?"?+?v.get());
?*?}
?*?}
?*
?*?高亮顯示?println
?*
?*?{@snippet?:
?*?class?HelloWorld?{
?*?????public?static?void?main(String...?args)?{
?*?????????System.out.println("Hello?World!");??????//?@highlight?substring="println"
?*?????}
?*?}
?*?}
?*
?*/
效果如下,更直觀,效果更好。

正則高亮代碼片段
甚至可以使用正則來高亮某一段中的某些關(guān)鍵詞:
/**
??*?正則高亮:
??*?{@snippet?:
??*???public?static?void?main(String...?args)?{
??*???????for?(var?arg?:?args)?{?????????????????//?@highlight?region?regex?=?"\barg\b"
??*???????????if?(!arg.isBlank())?{
??*???????????????System.out.println(arg);
??*???????????}
??*???????}??????????????????????????????????????//?@end
??*???}
??*???}
??*/
生成的 Javadoc 效果如下:

替換代碼片段
可以使用正則表達式來替換某一段代碼。
?/**
???*?正則替換:
???*?{@snippet?:
???*?class?HelloWorld?{
???*?????public?static?void?main(String...?args)?{
???*?????????System.out.println("Hello?World!");??//?@replace?regex='".*"'?replacement="..."
???*?????}
???*?}
???*?}
???*/
這段注釋會生成如下 Javadoc 效果。
class?HelloWorld?{
????public?static?void?main(String...?args)?{
????????System.out.println(...);
????}
}
附:Javadoc 生成方式
#?使用?javadoc?命令生成?Javadoc?文檔
???bin?./javadoc?-public?-sourcepath?./src?-subpackages?com?-encoding?utf-8?-charset?utf-8?-d?./javadocout
#?使用?Java?18?的?jwebserver?把生成的?Javadoc?發(fā)布測試
???bin?./jwebserver?-d?/Users/darcy/develop/javadocout
訪問測試:

JEP 416:使用方法句柄重新實現(xiàn)反射核心功能
Java 18 改進了 java.lang.reflect.Method、Constructor 的實現(xiàn)邏輯,使之性能更好,速度更快。這項改動不會改動相關(guān) API ,這意味著開發(fā)中不需要改動反射相關(guān)代碼,就可以體驗到性能更好反射。
OpenJDK 官方給出了新老實現(xiàn)的反射性能基準(zhǔn)測試結(jié)果。
Java 18 之前:
Benchmark?????????????????????????????????????Mode??Cnt???Score??Error??Units
ReflectionSpeedBenchmark.constructorConst?????avgt???10??68.049?±?0.872??ns/opReflectionSpeedBenchmark.constructorPoly??????avgt???10??94.132?±?1.805??ns/op
ReflectionSpeedBenchmark.constructorVar???????avgt???10??64.543?±?0.799??ns/op
ReflectionSpeedBenchmark.instanceFieldConst???avgt???10??35.361?±?0.492??ns/opReflectionSpeedBenchmark.instanceFieldPoly????avgt???10??67.089?±?3.288??ns/op
ReflectionSpeedBenchmark.instanceFieldVar?????avgt???10??35.745?±?0.554??ns/op
ReflectionSpeedBenchmark.instanceMethodConst??avgt???10??77.925?±?2.026??ns/op
ReflectionSpeedBenchmark.instanceMethodPoly???avgt???10??96.094?±?2.269??ns/op
ReflectionSpeedBenchmark.instanceMethodVar????avgt???10??80.002?±?4.267??ns/op
ReflectionSpeedBenchmark.staticFieldConst?????avgt???10??33.442?±?2.659??ns/op
ReflectionSpeedBenchmark.staticFieldPoly??????avgt???10??51.918?±?1.522??ns/op
ReflectionSpeedBenchmark.staticFieldVar???????avgt???10??33.967?±?0.451??ns/op
ReflectionSpeedBenchmark.staticMethodConst????avgt???10??75.380?±?1.660??ns/op
ReflectionSpeedBenchmark.staticMethodPoly?????avgt???10??93.553?±?1.037??ns/op
ReflectionSpeedBenchmark.staticMethodVar??????avgt???10??76.728?±?1.614??ns/op
Java 18 的新實現(xiàn):
Benchmark?????????????????????????????????????Mode??Cnt????Score???Error??Units
ReflectionSpeedBenchmark.constructorConst?????avgt???10???32.392?±?0.473??ns/opReflectionSpeedBenchmark.constructorPoly??????avgt???10??113.947?±?1.205??ns/op
ReflectionSpeedBenchmark.constructorVar???????avgt???10???76.885?±?1.128??ns/op
ReflectionSpeedBenchmark.instanceFieldConst???avgt???10???18.569?±?0.161??ns/opReflectionSpeedBenchmark.instanceFieldPoly????avgt???10???98.671?±?2.015??ns/op
ReflectionSpeedBenchmark.instanceFieldVar?????avgt???10???54.193?±?3.510??ns/op
ReflectionSpeedBenchmark.instanceMethodConst??avgt???10???33.421?±?0.406??ns/op
ReflectionSpeedBenchmark.instanceMethodPoly???avgt???10??109.129?±?1.959??ns/op
ReflectionSpeedBenchmark.instanceMethodVar????avgt???10???90.420?±?2.187??ns/op
ReflectionSpeedBenchmark.staticFieldConst?????avgt???10???19.080?±?0.179??ns/op
ReflectionSpeedBenchmark.staticFieldPoly??????avgt???10???92.130?±?2.729??ns/op
ReflectionSpeedBenchmark.staticFieldVar???????avgt???10???53.899?±?1.051??ns/op
ReflectionSpeedBenchmark.staticMethodConst????avgt???10???35.907?±?0.456??ns/op
ReflectionSpeedBenchmark.staticMethodPoly?????avgt???10??102.895?±?1.604??ns/op
ReflectionSpeedBenchmark.staticMethodVar??????avgt???10???82.123?±?0.629??ns/op
可以看到在某些場景下性能稍微好些。
JEP 417:Vector API(三次孵化)
在 Java 16 中引入一個新的 API 來進行向量計算,它可以在運行時可靠的編譯為支持的 CPU 架構(gòu),從而實現(xiàn)更優(yōu)的計算能力。
在 Java 17 中改進了 Vector API 性能,增強了例如對字符的操作、字節(jié)向量與布爾數(shù)組之間的相互轉(zhuǎn)換等功能。
現(xiàn)在在 JDK 18 中將繼續(xù)優(yōu)化其性能。
JEP 418:互聯(lián)網(wǎng)地址解析 SPI
對于互聯(lián)網(wǎng)地址解析 SPI,為主機地址和域名地址解析定義一個 SPI,以便java.net.InetAddress可以使用平臺內(nèi)置解析器以外的解析器。
InetAddress?inetAddress?=?InetAddress.getByName("www.wdbyte.com");
System.out.println(inetAddress.getHostAddress());
//?輸出
//?106.14.229.49
JEP 419:Foreign Function & Memory API (第二次孵化)
新的 API 允許 Java 開發(fā)者與 JVM 之外的代碼和數(shù)據(jù)進行交互,通過調(diào)用外部函數(shù),可以在不使用 JNI 的情況下調(diào)用本地庫。
這是一個孵化功能;需要添加--add-modules jdk.incubator.foreign來編譯和運行 Java 代碼,Java 18 改進了相關(guān) API ,使之更加簡單易用。
歷史
Java 14 JEP 370 (opens new window)[42]引入了外部內(nèi)存訪問 API(孵化器)。 Java 15 JEP 383 (opens new window)[43]引入了外部內(nèi)存訪問 API(第二孵化器)。 Java 16 JEP 389 (opens new window)[44]引入了外部鏈接器 API(孵化器)。 Java 16 JEP 393 (opens new window)[45]引入了外部內(nèi)存訪問 API(第三孵化器)。 Java 17 JEP 412 (opens new window)[46]引入了外部函數(shù)和內(nèi)存 API(孵化器)。
JEP 420:switch 表達式(二次孵化)
從 Java 17 開始,對于 Switch 的改進就已經(jīng)在進行了,Java 17 的 JEP 406 已經(jīng)對 Switch 表達式進行了增強,使之可以減少代碼量。
下面是幾個例子:
//?JDK?17?以前
static?String?formatter(Object?o)?{
????String?formatted?=?"unknown";
????if?(o?instanceof?Integer?i)?{
????????formatted?=?String.format("int?%d",?i);
????}?else?if?(o?instanceof?Long?l)?{
????????formatted?=?String.format("long?%d",?l);
????}?else?if?(o?instanceof?Double?d)?{
????????formatted?=?String.format("double?%f",?d);
????}?else?if?(o?instanceof?String?s)?{
????????formatted?=?String.format("String?%s",?s);
????}
????return?formatted;
}
而在 Java 17 之后,可以通過下面的寫法進行改進:
//?JDK?17?之后
static?String?formatterPatternSwitch(Object?o)?{
????return?switch?(o)?{
????????case?Integer?i?->?String.format("int?%d",?i);
????????case?Long?l????->?String.format("long?%d",?l);
????????case?Double?d??->?String.format("double?%f",?d);
????????case?String?s??->?String.format("String?%s",?s);
????????default????????->?o.toString();
????};
}
switch 可以和 null 進行結(jié)合判斷:
static?void?testFooBar(String?s)?{
????switch?(s)?{
????????case?null?????????->?System.out.println("Oops");????????case?"Foo",?"Bar"?->?System.out.println("Great");
????????default???????????->?System.out.println("Ok");
????}
}
case 時可以加入復(fù)雜表達式:
static?void?testTriangle(Shape?s)?{
????switch?(s)?{
????????case?Triangle?t?&&?(t.calculateArea()?>?100)?->????????????System.out.println("Large?triangle");
????????default?->
????????????System.out.println("A?shape,?possibly?a?small?triangle");
????}
}
case 時可以進行類型判斷:
sealed?interface?S?permits?A,?B,?C?{}
final?class?A?implements?S?{}
final?class?B?implements?S?{}
record?C(int?i)?implements?S?{}??//?Implicitly?final
static?int?testSealedExhaustive(S?s)?{
????return?switch?(s)?{
????????case?A?a?->?1;
????????case?B?b?->?2;
????????case?C?c?->?3;
????};
}
擴展:JEP 406:Switch 的類型匹配(預(yù)覽)[47]
JEP 421:棄用刪除相關(guān)
在未來將刪除 Finalization,目前 Finalization 仍默認保持啟用狀態(tài),但是已經(jīng)可以手動禁用;在未來的版本中,將會默認禁用;在以后的版本中,它將被刪除。需要進行資源管理可以嘗試 try-with-resources 或者 java.lang.ref.Cleaner。
參考資料
恢復(fù)始終嚴(yán)格的浮點語義: https://openjdk.java.net/jeps/306
[2]增強的偽隨機數(shù)生成器: https://openjdk.java.net/jeps/356
[3]使用新的 macOS 渲染庫: https://openjdk.java.net/jeps/382
[4]支持 macOS/AArch64 架構(gòu): https://openjdk.java.net/jeps/391
[5]刪除已啟用的 Applet API: https://openjdk.java.net/jeps/398
[6]更強的封裝 JDK 內(nèi)部封裝: https://openjdk.java.net/jeps/403
[7]Switch 模式匹配(預(yù)覽): https://openjdk.java.net/jeps/406
[8]移除 RMI Activation: https://openjdk.java.net/jeps/407
[9]密封類(Sealed Classes): https://openjdk.java.net/jeps/409
[10]JEP 401:移除實驗性的 AOT 和 JIT 編譯器: https://openjdk.java.net/jeps/410
[11]棄用 Security Manager: https://openjdk.java.net/jeps/411
[12]外部函數(shù)和內(nèi)存 API(孵化器): https://openjdk.java.net/jeps/412
[13]Vector API(第二孵化器): https://openjdk.java.net/jeps/414
[14]指定上下文的反序列化過濾器: https://openjdk.java.net/jeps/415
[15]增強的偽隨機數(shù)生成器: https://openjdk.java.net/jeps/356
[16]macOS Mojave 10.14 Release Notes: https://developer.apple.com/documentation/macos-release-notes/macos-mojave-10_14-release-notes?preferredLanguage=occ#3035786
[17]Apple Metal: https://developer.apple.com/metal/
[18]Java 16 新功能介紹 - JEP 386: https://www.wdbyte.com/java/java-16/
[19]關(guān)鍵內(nèi)部 API: https://openjdk.java.net/jeps/260#Description
[20]JEP 403:更強的 JDK 內(nèi)部封裝: https://openjdk.java.net/jeps/403
[21]Java 16 新功能介紹: https://www.wdbyte.com/java/java-16/
[22]JEP 406:switch 的類型匹配(預(yù)覽): https://openjdk.java.net/jeps/406
[23]JEP 407:移除 RMI Activation: https://openjdk.java.net/jeps/407
[24]Java 16 新功能介紹: https://www.wdbyte.com/java/java-16/
[25]JEP 409: Sealed Classes: https://openjdk.java.net/jeps/409
[26]JEP 370: https://openjdk.java.net/jeps/370
[27]JEP 383: https://openjdk.java.net/jeps/383
[28]JEP 389: https://openjdk.java.net/jeps/389
[29]JEP 393: https://openjdk.java.net/jeps/393
[30]JEP 412: https://openjdk.java.net/jeps/412
[31]JEP 412:外部函數(shù)和內(nèi)存 API (孵化): https://openjdk.java.net/jeps/412
[32]JEP 415:指定上下文的反序列化過濾器: https://openjdk.java.net/jeps/415
[33]默認為 UTF-8: https://openjdk.java.net/jeps/400
[34]簡單的網(wǎng)絡(luò)服務(wù)器: https://openjdk.java.net/jeps/408
[35]Java API 文檔中的代碼片段: https://openjdk.java.net/jeps/413
[36]使用方法句柄重新實現(xiàn)核心反射: https://openjdk.java.net/jeps/416
[37]Vector API(三次孵化): https://openjdk.java.net/jeps/417
[38]互聯(lián)網(wǎng)地址解析 SPI: https://openjdk.java.net/jeps/418
[39]Foreign Function & Memory API (二次孵化): https://openjdk.java.net/jeps/419
[40]switch 模式匹配(二次預(yù)覽): https://openjdk.java.net/jeps/420
[41]棄用完成刪除: https://openjdk.java.net/jeps/421
[42]JEP 370 (opens new window): https://openjdk.java.net/jeps/370
[43]JEP 383 (opens new window): https://openjdk.java.net/jeps/383
[44]JEP 389 (opens new window): https://openjdk.java.net/jeps/389
[45]JEP 393 (opens new window): https://openjdk.java.net/jeps/393
[46]JEP 412 (opens new window): https://openjdk.java.net/jeps/412
[47]JEP 406:Switch 的類型匹配(預(yù)覽): https://www.wdbyte.com/java/java-17/#_7-jep-406-switch-的類型匹配-預(yù)覽
··········? END? ··············
歡迎加入我的知識星球獲取更多面試干貨,《Java 面試指北》持續(xù)更新完善中!

近期文章精選?:
如果本文對你有幫助的話,歡迎點贊&在看&分享,這對我繼續(xù)分享&創(chuàng)作優(yōu)質(zhì)文章非常重要。感謝????
