<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          從 Java 12 到 Java 17 那些激動(dòng)人心的新特性

          共 6393字,需瀏覽 13分鐘

           ·

          2022-01-18 18:05


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


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


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


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


          ?1:封印類


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


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


          也就是說,只有 Red、Blue 和 Yellow 可以繼承這個(gè)類,其他類想要繼承它都無法通過編譯。


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


          public?abstract?sealed class?Color?{...}
          ... class?Red?????extends?Color?{...}
          ... class?Blue????extends?Color?{...}
          ... class?Yellow??extends?Color?{...}


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


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


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


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


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


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


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


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


          這絕對是個(gè)救星!


          3:switch 表達(dá)式


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


          String?adjacentColor = switch?(color) {
          ????case?Blue, Green -> "yellow";
          ????case?Red, Purple -> "blue";
          ????case?Yellow, Orange -> "red";
          ????default?????????????-> "Unknown Color";
          };


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


          一個(gè)明顯的區(qū)別是沒有了 break 語句。switch 表達(dá)式延續(xù)了 Oracle 讓 Java 語法更簡潔的趨勢。Oracle 非常討厭大多數(shù) switch 語句包含很多的 CASE BREAK、CASE BREAK、CASE BREAK……。


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


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


          String adjacentColor = switch?(color) {
          ????case?Blue, Green -> "yellow";
          ????case?Red, Purple -> "blue";
          ????case?Yellow, Orange -> "red";
          ????default?????????????-> {
          ????System.out.println("The color could not be found.");
          ????yield?"Unknown Color";
          ??}
          };


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


          總的來說,switch 表達(dá)式是一種更簡潔的 switch 語句,但它不會(huì)取代 switch 語句,這兩種語句都可用。


          4:文本塊


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


          String text = """
          Hello
          World"""
          ;


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


          String text = """
          You can "quote" without complaints!"""
          ; // You can "quote"?without complaints!


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


          String text = """
          The only necessary escape is \"""
          ,
          everything else?is?maintained.""";


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


          String name = "Chris";
          String text = """
          My name is %s."""
          .format(name); // My name is?Chris.


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


          String text1 = """
          No trailing spaces.
          Trailing spaces. \s"""
          ;


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


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


          5:record 類


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


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

          }


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


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


          public?record Coord(int?x, int?y)?{
          ??public?boolean?isCenter()?{
          ????return?x() == 0?&& y() == 0;
          ??}

          ??public?static?boolean?isCenter(Coord coord)?{
          ????return?coord.x() == 0?&& coord.y() == 0;
          ??}
          }
          record 類可以有多個(gè)構(gòu)造器:

          public?record Coord(int?x, int?y)?{
          ??public?Coord()?{
          ????this(0,0); // The default constructor is still implemented.
          ??}
          }


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


          public?record Coord(int?x, int?y)?{
          ??public?Coord(int?x, int?y)?{
          ????this.x = x;
          ????this.y = y;
          ??} // Will replace the default constructor.
          }


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


          6:模式匹配


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


          if?(o instanceof Car) {
          ??System.out.println(((Car) o).getModel());
          }


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


          if?(o instanceof Car c) {
          ??System.out.println(c.getModel());
          }


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


          if?(!(o instance of Car c)) {
          ??System.out.println("This isn't a car at all!");
          } else?{
          ??System.out.println(c.getModel());
          }


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


          public?boolean?isHonda(Object?o) {
          ??return?o instanceof?Car c && c.getModel().equals("Honda");
          }


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


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


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


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


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

          來源:infoq.com/articles/six-features-jdk12-to-jdk17/



          往期推薦



          使用MySQL的JSON數(shù)據(jù)類型,事半功倍!

          不要再封裝各種 Util 工具類了,這款開源項(xiàng)目,真的很好用!

          Eclipse 跌落“神壇”,這款 IDE 后來居上!

          推薦一個(gè) Spring Boot 快速開發(fā)利器

          更快 Maven 來襲,性能大幅提升!

          Kafka那些值得我們學(xué)習(xí)的優(yōu)秀設(shè)計(jì)



          瀏覽 55
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  豆花视频网站 | 日韩一级电影院 | 久久久福利视频 | 最新亚洲国产黄色视频在线观看 | 一本色道久久综合亚洲精品苍井空 |