應(yīng)該知道的從 Java 12 到 Java 17 那些激動(dòng)人心的新特性

2021 年 9 月怎抛,Oracle 發(fā)布了 Java 17偿乖,Java 的下一個(gè)長(zhǎng)期支持版本矗钟。如果你在使用 Java 8 或 Java 11新症,可能不會(huì)注意到 Java 12 之后新增的一些很酷的新特性恳蹲。

因?yàn)檫@是一個(gè)很重要的版本虐块,我會(huì)突出介紹一些我個(gè)人很感興趣的新特性!

需要注意的是嘉蕾,Java 中的大多數(shù)變更首先需要經(jīng)過(guò)“預(yù)覽”階段贺奠,也就是說(shuō)它們被添加到一個(gè)版本中,但還沒(méi)有完成错忱。人們可以嘗試使用它們儡率,但不建議將其用在生產(chǎn)環(huán)境中。

這里所列舉的所有特性都已正式添加到 Java 中以清,并且已經(jīng)過(guò)了預(yù)覽階段儿普。

1:封印類(lèi)

在 Java 15 中處于預(yù)覽階段并在 Java 17 中成為正式特性的封印類(lèi)?,提供了一種新的繼承規(guī)則限定方法掷倔。當(dāng)你在類(lèi)或接口前面添加 sealed 關(guān)鍵字的同時(shí)眉孩,也添加了一個(gè)允許擴(kuò)展這個(gè)類(lèi)或?qū)崿F(xiàn)這個(gè)接口的類(lèi)的清單。例如,如果你定義了一個(gè)類(lèi):

public abstract sealed class?Color?permits?Red, Blue, Yellow

復(fù)制代碼

也就是說(shuō)浪汪,只有 Red障贸、Blue 和 Yellow 可以繼承這個(gè)類(lèi),其他類(lèi)想要繼承它都無(wú)法通過(guò)編譯吟宦。

你也可以不使用 permits 關(guān)鍵字篮洁,然后將類(lèi)定義與類(lèi)放在相同的文件中,如下所示:

public abstract sealed class?Color?{...}

復(fù)制代碼

注意殃姓,這些子類(lèi)并不是嵌套在封印類(lèi)中袁波,而是放在類(lèi)定義之后。這與使用關(guān)鍵字 permit 是一樣的效果蜗侈,可以擴(kuò)展 Color 的類(lèi)只有 Red篷牌、Blue 和 Yellow。

那么踏幻,封印類(lèi)通常用在哪里枷颊?通過(guò)限定繼承規(guī)則,同時(shí)也限定了封裝規(guī)則该面。假設(shè)你正在開(kāi)發(fā)一個(gè)庫(kù)夭苗,并且需要將抽象類(lèi) Color 包含在其中。你知道 Color 這個(gè)類(lèi)以及哪些類(lèi)需要擴(kuò)展它隔缀,但如果它被聲明為 public 的题造,那么你有什么辦法可以阻止外部代碼擴(kuò)展它?

如果有人誤解了它的用途并用 Square 對(duì)它進(jìn)行了擴(kuò)展猾瘸,該怎么辦界赔?這符合你的意圖嗎?或者你其實(shí)是想讓 Color 保持私有牵触?但即使是這樣淮悼,包級(jí)別的可見(jiàn)性也不能避免所有問(wèn)題。如果后來(lái)有人對(duì)這個(gè)庫(kù)進(jìn)行了擴(kuò)展了該怎么辦揽思?他們?nèi)绾文軌蛑滥阒淮蛩阕屢恍〔糠诸?lèi)集成 Color袜腥?

封印類(lèi)不僅可以保護(hù)你的代碼不受外部代碼的影響,還是一種向你可能從未見(jiàn)過(guò)的人傳達(dá)意圖的方式绰更。如果一個(gè)類(lèi)是封印的瞧挤,你是在傳達(dá)只有某些類(lèi)可以擴(kuò)展它。這種健壯性可以確保在多年以后任何閱讀你代碼的人都會(huì)理解代碼的嚴(yán)謹(jǐn)儡湾。

2:增強(qiáng)的空指針異常

增強(qiáng)的空指針異常?是一個(gè)有趣的更新——不會(huì)太復(fù)雜特恬,但仍然很受歡迎。這個(gè)增強(qiáng)在 Java 14 中正式發(fā)布徐钠,提高了空指針異常(NullPointerException癌刽,簡(jiǎn)稱(chēng) NPE)的可讀性,可以打印出在拋出異常位置所調(diào)用的方法的名稱(chēng)和空變量的名稱(chēng)。例如显拜,如果你調(diào)用 a.b.getName()衡奥,而 b 為空,那么異常的堆棧跟蹤信息會(huì)告訴你調(diào)用 getName()失敗远荠,因?yàn)?b 是空的矮固。

我們都知道,NPE 是一種非常常見(jiàn)的異常譬淳,雖然在大多數(shù)情況下找出導(dǎo)致拋出異常的根源并不難档址,但你會(huì)時(shí)不時(shí)地遇到同時(shí)有兩三個(gè)可疑變量的情況。你進(jìn)入調(diào)試模式邻梆,開(kāi)始查看代碼守伸,但問(wèn)題很難重現(xiàn)。你只能試著回憶最初做了什么導(dǎo)致拋出 NPE 的浦妄。

如果你能提前獲得這些信息尼摹,就不用這些麻煩地調(diào)試了。這就是這個(gè)特性的閃光點(diǎn):不用再猜測(cè) NPE 是從哪里拋出來(lái)的剂娄。在關(guān)鍵時(shí)刻蠢涝,當(dāng)你遇到難以重現(xiàn)的異常場(chǎng)景時(shí),你就有了解決問(wèn)題所需的一切宜咒。

這絕對(duì)是個(gè)救星惠赫!

3:switch 表達(dá)式

希望你耐心聽(tīng)我說(shuō)幾句——switch表達(dá)式?(在 Java 12 中預(yù)覽,并正式添加到 Java 14 中)是 switch 語(yǔ)句和 lambda 之間的某種結(jié)合故黑。真的,當(dāng)我第一次向別人描述 switch 表達(dá)式時(shí)庭砍,我的說(shuō)法是他們把 switch 語(yǔ)句 lambda 化了场晶。請(qǐng)看下面這個(gè)語(yǔ)法:

String adjacentColor = switch (color) {

復(fù)制代碼

現(xiàn)在明白我的意思了嗎?

一個(gè)明顯的區(qū)別是沒(méi)有了 break 語(yǔ)句怠缸。switch 表達(dá)式延續(xù)了 Oracle 讓 Java 語(yǔ)法更簡(jiǎn)潔的趨勢(shì)诗轻。Oracle 非常討厭大多數(shù) switch 語(yǔ)句包含很多的 CASE BREAK、CASE BREAK揭北、CASE BREAK……扳炬。

老實(shí)說(shuō),他們討厭這個(gè)是對(duì)的搔体,因?yàn)槿藗兒苋菀自谶@個(gè)地方犯錯(cuò)恨樟。我們當(dāng)中是否有人敢說(shuō)他們從來(lái)沒(méi)有遇到過(guò)這種情況:忘記在 switch 里添加 break 語(yǔ)句,只有當(dāng)代碼在運(yùn)行時(shí)發(fā)生崩潰才知道疚俱?switch 表達(dá)式通過(guò)一種有趣的方式修復(fù)了這個(gè)問(wèn)題劝术,你只需要用逗號(hào)隔開(kāi)同一個(gè)代碼塊里所有的值。沒(méi)錯(cuò),不需要使用 break 了养晋!它會(huì)替你處理好衬吆!

switch 表達(dá)式還新增了 yield 關(guān)鍵字。如果一個(gè) case 進(jìn)入了一個(gè)代碼塊绳泉,yield 將被作為 switch 表達(dá)式的返回語(yǔ)句逊抡。例如,如果我們將上面的代碼稍作修改:

String adjacentColor = switch (color) {

復(fù)制代碼

在默認(rèn) case 里零酪,System.out.println()方法將被執(zhí)行冒嫡,adjacentColor 變量最終的值是“Unknown Color”,因?yàn)檫@是 yield 返回的結(jié)果蛾娶。

總的來(lái)說(shuō)灯谣,switch 表達(dá)式是一種更簡(jiǎn)潔的 switch 語(yǔ)句,但它不會(huì)取代 switch 語(yǔ)句蛔琅,這兩種語(yǔ)句都可用胎许。

4:文本塊

文本塊?特性在 Java 13 中預(yù)覽,并正式添加到 Java 15 中罗售,它可以簡(jiǎn)化多行字符串的寫(xiě)法辜窑,支持換行,并在不需要轉(zhuǎn)義字符的情況下保持縮進(jìn)寨躁。要?jiǎng)?chuàng)建一個(gè)文本塊穆碎,只需要這樣:

String text = """

復(fù)制代碼

注意,這個(gè)變量仍然是一個(gè)字符串职恳,只是它隱含了換行和制表符所禀。同樣,如果我們想要使用引號(hào)放钦,也不需要轉(zhuǎn)義字符:

String text = """

復(fù)制代碼

唯一需要使用反斜杠轉(zhuǎn)義字符的地方是當(dāng)你想要在文本塊里包含""":

String text = """

復(fù)制代碼

除此之外色徘,你可以調(diào)用 String 的 format()方法,用動(dòng)態(tài)內(nèi)容替換文本塊中的占位符:

String name = "Chris";

復(fù)制代碼

每行后面的空格都會(huì)被剪切掉操禀,除非你指定了'\s'褂策,這是文本塊的一個(gè)轉(zhuǎn)義字符:

String text1 = """

復(fù)制代碼

那么,在什么情況下會(huì)使用文本塊呢颓屑?除了能夠?qū)Υ髩K的文本進(jìn)行格式化外斤寂,將代碼片段粘貼到字符串中也變得非常容易。因?yàn)榭s進(jìn)被保留了揪惦,如果你要寫(xiě)一個(gè) HTML 或 Python 代碼塊遍搞,或使用其他任何語(yǔ)言,你都可以按照正常的方式寫(xiě)好它們丹擎,然后用"""把它們括起來(lái)尾抑,就可以保留代碼的格式歇父。你甚至可以用文本塊來(lái)編寫(xiě) JSON,并使用 format()方法輕松地插入值再愈。

總的來(lái)說(shuō)榜苫,這是個(gè)一個(gè)很方便的特性。雖然文本塊看起來(lái)只是一個(gè)小功能翎冲,但從長(zhǎng)遠(yuǎn)來(lái)看垂睬,類(lèi)似這種可以提升開(kāi)發(fā)效率的小功能會(huì)逐漸增加。

5:record 類(lèi)

record類(lèi)?在 Java 14 中預(yù)覽抗悍,并正式添加到 Java 16 中驹饺,是一種數(shù)據(jù)類(lèi),處理所有與 POJO 相關(guān)的樣板代碼缴渊。也就是說(shuō)赏壹,如果你聲明了一個(gè) record 類(lèi):

public record?Coord(int x, int y) {

復(fù)制代碼

equals()和 hashcode()方法會(huì)自動(dòng)實(shí)現(xiàn),toString()將返回這個(gè)類(lèi)實(shí)例包含的所有字段的值衔沼,最重要的是蝌借,x()和 y()將分別返回 x 和 y 的值。想想你之前寫(xiě)過(guò)的 POJO 類(lèi)指蚁,并想象一下用 record 類(lèi)來(lái)代替它們會(huì)怎樣菩佑。是不是好看多了?省了多少事了凝化?

除此之外稍坯,record 類(lèi)是 final 和不可變的——不能被繼承,并且類(lèi)實(shí)例一旦被創(chuàng)建搓劫,它的字段就不能被修改瞧哟。你可以在 record 類(lèi)中聲明方法,包括非靜態(tài)方法和靜態(tài)方法:

public record?Coord(int x, int y) {

復(fù)制代碼

record 類(lèi)可以有多個(gè)構(gòu)造器:

public record?Coord(int x, int y) {

復(fù)制代碼

需要注意的是枪向,當(dāng)你在 record 類(lèi)中聲明自定義構(gòu)造函數(shù)時(shí)绢涡,必須調(diào)用默認(rèn)構(gòu)造函數(shù)。否則遣疯,record 類(lèi)將不知道如何處理它的值。如果你聲明了一個(gè)與默認(rèn)構(gòu)造函數(shù)一樣的構(gòu)造函數(shù)凿傅,你要初始化所有的字段:

public record?Coord(int x, int y) {

復(fù)制代碼

關(guān)于 record 類(lèi)缠犀,有很多可討論的話(huà)題。這是一個(gè)大的變更聪舒,在合適的地方使用它們辨液,它們會(huì)非常有用。我在這里沒(méi)有涵蓋所有內(nèi)容箱残,但希望這能讓你了解它們所提供的能力滔迈。

6:模式匹配

模式匹配?是 Oracle 在與 Java 冗長(zhǎng)語(yǔ)法的斗爭(zhēng)中做出的另一個(gè)舉措止吁。模式匹配在 Java 14 和 Java 15 中預(yù)覽過(guò),并正式添加到 Java 16 中燎悍,它可以在 instanceof 條件得到滿(mǎn)足后消除不必要的類(lèi)型轉(zhuǎn)換敬惦。例如,我們都很熟悉這樣的代碼:

if (o instanceof Car) {

復(fù)制代碼

如果你想要訪(fǎng)問(wèn) Car 的方法谈山,必要要這么做俄删。在第二行,o 是 Car 的實(shí)例奏路,這是毫無(wú)疑問(wèn)的畴椰,instanceof 已經(jīng)確認(rèn)了這一點(diǎn)。如果我們使用模式匹配鸽粉,只要做一個(gè)小小的改變:

if (o instanceof Car c) {

復(fù)制代碼

現(xiàn)在斜脂,所有的對(duì)象類(lèi)型轉(zhuǎn)換都由編譯器完成〈セ看起來(lái)改變很小帚戳,但它避免了很多樣板代碼。這也適用于條件分支威兜,當(dāng)你進(jìn)入一個(gè)已經(jīng)明確了對(duì)象類(lèi)型的分支:

if (!(o instance of Car c)) {

復(fù)制代碼

你甚至可以在 instanceof 那一行使用模式匹配:

public boolean?isHonda(Object o) {

復(fù)制代碼

雖然模式匹配不像其他一些變更那么大销斟,但還是簡(jiǎn)化了常用的代碼。

Java 17 將繼續(xù)演進(jìn)

當(dāng)然椒舵,Java 12 到 Java 17 并不是只推出了這些更新蚂踊,這些只是我認(rèn)為比較有趣的部分。用最新的 Java 版本來(lái)運(yùn)行大型項(xiàng)目需要很大的勇氣笔宿,如果是從 Java 8 遷移過(guò)來(lái)犁钟,則更需要勇氣。

如果有人猶豫不決泼橘,是可以理解的涝动。但是,即使你沒(méi)有遷移計(jì)劃炬灭,或者某個(gè)升級(jí)計(jì)劃可能持續(xù)數(shù)年之久醋粟,跟上語(yǔ)言新特性的變化總歸是件好事。我希望我分享的這些內(nèi)容能夠讓它們更加深入人心重归,讓閱讀過(guò)這些內(nèi)容的人都可以開(kāi)始考慮如何使用它們米愿!

Java 17 很特別——它是下一個(gè)長(zhǎng)期支持版本,接過(guò)了 Java 11 的接力棒鼻吮,并且很可能在未來(lái)幾年內(nèi)成為遷移最多的 Java 版本育苟。即使你現(xiàn)在還沒(méi)有做好準(zhǔn)備,可以開(kāi)始學(xué)習(xí)起來(lái)了椎木,當(dāng)你身處基于 Java 17 的項(xiàng)目當(dāng)中违柏,你已經(jīng)是一名經(jīng)驗(yàn)豐富的開(kāi)發(fā)者博烂!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市漱竖,隨后出現(xiàn)的幾起案子禽篱,更是在濱河造成了極大的恐慌,老刑警劉巖闲孤,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谆级,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡讼积,警方通過(guò)查閱死者的電腦和手機(jī)肥照,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)勤众,“玉大人舆绎,你說(shuō)我怎么就攤上這事∶茄眨” “怎么了吕朵?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)窥突。 經(jīng)常有香客問(wèn)我努溃,道長(zhǎng),這世上最難降的妖魔是什么阻问? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任梧税,我火速辦了婚禮,結(jié)果婚禮上称近,老公的妹妹穿的比我還像新娘第队。我一直安慰自己,他們只是感情好刨秆,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布凳谦。 她就那樣靜靜地躺著,像睡著了一般衡未。 火紅的嫁衣襯著肌膚如雪尸执。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天缓醋,我揣著相機(jī)與錄音剔交,去河邊找鬼。 笑死改衩,一個(gè)胖子當(dāng)著我的面吹牛驯镊,可吹牛的內(nèi)容都是我干的葫督。 我是一名探鬼主播竭鞍,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼洽胶!你這毒婦竟也來(lái)了晒夹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤姊氓,失蹤者是張志新(化名)和其女友劉穎丐怯,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體翔横,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡读跷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了禾唁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片效览。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖荡短,靈堂內(nèi)的尸體忽然破棺而出丐枉,到底是詐尸還是另有隱情,我是刑警寧澤掘托,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布瘦锹,位于F島的核電站,受9級(jí)特大地震影響烫映,放射性物質(zhì)發(fā)生泄漏沼本。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一锭沟、第九天 我趴在偏房一處隱蔽的房頂上張望抽兆。 院中可真熱鬧,春花似錦族淮、人聲如沸辫红。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)贴妻。三九已至,卻和暖如春蝙斜,著一層夾襖步出監(jiān)牢的瞬間名惩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工孕荠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娩鹉,地道東北人攻谁。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像弯予,于是被迫代替她去往敵國(guó)和親戚宦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容