Java 23 包含全新和更新的 Java 語言功能、核心 API 以及 JVM,同時適合新的 Java 開發(fā)者和高級開發(fā)者。從IntelliJ IDEA 2024.2開始已支持 Java 23 功能。
跟上 Java 新版本的發(fā)布節(jié)奏可能很難,這意味著要解決一連串的問題——更改是什么、為什么要更改以及如何使用全新和更新的功能。
在這篇博文中,我將介紹 Java 23 的一些全新和更新功能 – 它們?yōu)槟鉀Q的痛點、語法和語義,以及 IntelliJ IDEA 如何幫助您使用它們。
我將重點介紹 Java 23 功能,例如在模式匹配中包含基元數(shù)據(jù)類型、在代碼庫中導入模塊的能力、在文檔注釋中使用 Markdown 的可能性、隱式聲明的類與實例 main 方法,以及靈活的構(gòu)造函數(shù)體。
如果您感興趣,請訪問此鏈接來查看 Java 23 其他功能的列表。
在深入了解 Java 23 功能的詳細信息之前,我們先快速配置 IntelliJ IDEA。
IntelliJ IDEA 配置
IntelliJ IDEA 2024.2開始已經(jīng)支持 Java 23。
在您的 Project Settings(項目設(shè)置)中,將 SDK 設(shè)置為 Java 23。您可以將 IntelliJ IDEA 配置為使用下載版本的 JDK 23,也可以選擇從供應(yīng)商列表中下載而無需退出 IDE。對于語言級別,選擇“23(Preview) – Primitive types in patterns, implicitly declared classes, etc.”(23(預(yù)覽) – 模式中的基元類型,隱式聲明的類等),如下面的屏幕截圖中所示:
要使用 Markdown 文檔注釋等正式功能,請將語言級別更改為“23 – Markdown documentation comments”(23 – Markdown 文檔注釋),如以下設(shè)置屏幕截圖中所示:
在掌握 IntelliJ IDEA 的配置后,我們來深入學習新功能。
模式、instanceof 和 switch 中
的基元類型(預(yù)覽功能)
想象一下,您需要編寫一個條件構(gòu)造,它基于 long 變量的值是否匹配幾個字面量值或落在某個值范圍內(nèi)來執(zhí)行代碼。
您會怎么做?在此之前,您只能使用 if/else 構(gòu)造執(zhí)行此操作。但是,借助 Java 23 中的模式、instanceof 和 switch 中的基元類型(一種預(yù)覽語言功能),您可以使用更具表達性且易于閱讀的 switch 構(gòu)造來編寫此功能,同時在 case 標簽中使用 long 值。
將基元類型添加到模式匹配中
意味著什么?
在 Java 23 之前,switch 構(gòu)造(語句和表達式)僅能處理引用變量和一些基元數(shù)據(jù)類型,例如 int、byte、short(有約束)。此外,instanceof 運算符不能用于任何基元數(shù)據(jù)類型。
借助 Java 23,您可以將所有基元數(shù)據(jù)類型(包括 boolean、long、float 和 double)與 Switch 構(gòu)造中的模式匹配和 instanceof 運算符一起使用。這適用于在嵌套和頂層上下文中使用。
為什么您應(yīng)該關(guān)注此功能?一項功能的價值取決于它影響的代碼庫有多大以及使用頻率。由于條件語句是編程的基礎(chǔ)之一,您可以預(yù)期在代碼庫中大量使用此功能。即使您可能不會編寫代碼,您也會閱讀由其他人編寫的代碼。
我們通過一個示例來理解此功能。
一個示例(將較長的 if-else 語句
替換為 switch 表達式)
想象一個方法,例如 getHTTPCodeDesc(int),它接受 HTTP 服務(wù)器代碼作為 int 值,并返回相應(yīng)的字符串表示,同時將其與某個字面量值或值范圍進行比較。
這段代碼似乎沒有明顯的問題 – 我們都編寫過或閱讀過類似的代碼。不過,處理 if-else 構(gòu)造的流程可能需要更長的時間,因為它們可能定義不僅限于一個變量的復(fù)雜條件。我們簡單地假設(shè)方法 getHTTPCodeDesc() 的定義如下:
publicStringgetHTTPCodeDesc(intcode){ if(code==100){ return"Continue"; } elseif(code==200){ return"OK"; } elseif(code==301){ return"Movedpermanently"; } elseif(code==302){ return"Found"; } elseif(code==400){ return"Badrequest"; } elseif(code==500){ return"Internalservererror"; } elseif(code==502){ return"Badgateway"; } elseif(code>100&&code200)?{ ???????return?"Informational"; ???}? ???else?if?(code?>200&&code300)?{ ???????return?"Successful"; ???}? ???else?if?(code?>302&&code400)?{ ???????return?"Redirection"; ???}? ???else?if?(code?>400&&code500)?{ ???????return?"Client?error"; ???}? ???else?if?(code?>502&&code600)?{ ???????return?"Server?error"; ???}? ???else?{ ???????return?"Unknown?error"; ???} }
在 Java 23 中,可以使用 switch 表達式(使用基元作為模式)替換上述代碼,具體如下所示:
publicStringgetHTTPCodeDesc(intcode){ returnswitch(code){ case100->"Continue"; case200->"OK"; case301->"MovedPermanently"; case302->"Found"; case400->"BadRequest"; case500->"InternalServerError"; case502->"BadGateway"; caseintiwheni>100&&i200?->"Informational"; caseintiwheni>200&&i300?->"Successful"; caseintiwheni>302&&i400?->"Redirection"; caseintiwheni>400&&i500?->"ClientError"; caseintiwheni>502&&i600?->"ServerError"; default->"Unknownerror"; }; }
上述代碼的第一個明顯好處是,相比于使用 if-else 語句的版本,它更易于閱讀和理解。您可以一目了然地理解代碼邏輯。
另一個不那么明顯的好處(但也很重要)是上述代碼如何減少您的認知負擔。認知負擔指的是您在工作記憶中擁有的信息量(工作記憶空間有限)。如果您試圖用與您的最終目標無直接關(guān)聯(lián)的指令或信息來使您的工作記憶超載,那么您的工作效率會降低。易于閱讀的代碼段可以幫助您將注意力集中到代碼的其他領(lǐng)域。當我們探討如何經(jīng)常從中受益時,這些小的勝利會起到很大作用。
現(xiàn)在,我們來聊聊簡單的部分,我是指語法。正如您所注意到的,利用帶保護的 (when i > 100 && i < 200) 類型模式 (int i),帶保護的 case 標簽既可以有常量值(例如 100、200 等),也可以有使用模式匹配指定的值范圍。您也可以定義一個 default 子句。
在上述代碼中,方法 getHTTPCodeDesc() 使用 switch 表達式返回一個值。無論您傳遞給方法形參(即 code)的值如何,該方法都必須返回一個值。換句話說,switch 表達式必須為詳盡。如果不是,IntelliJ IDEA 可以檢測到并提供添加 default 子句的選項,如以下 GIF 中所示:
上述代碼在 int 類型的變量上進行切換。類似地,您可以在所有其他基元類型(例如 long、double、float 等)的變量上切換。
您是第一次使用模式匹配還是
首次了解 switch 構(gòu)造的最近更改?
如果您對模式匹配完全不熟悉,請查看我的博文 Java 17 和 IntelliJ IDEA 中關(guān)于基礎(chǔ)知識的部分。如果您對如何將模式匹配與 switch 構(gòu)造配合使用感興趣,我有關(guān)于此主題的另一篇詳細博文:Evolution of the Switch Construct in Java—Why Should you Care?。這篇文章介紹了 switch 構(gòu)造如何使用模式匹配來檢查引用值是否符合不同模式,并根據(jù)變量的類型及其特性有條件地執(zhí)行代碼。
將模式匹配與布爾值配合使用
我們經(jīng)常閱讀和編寫根據(jù) boolean 變量的值是 true 還是 false 來返回值的代碼。例如,在以下代碼中,方法 calculateDiscount 根據(jù)您傳遞給方法形參 isPremiumMember 的值是 true 還是 false 來計算并返回折扣值:
publicclassDiscountCalculator{ privatestaticfinalintPREMIUM_DISCOUNT_PERCENTAGE=20; privatestaticfinalintREGULAR_DISCOUNT_PERCENTAGE=5; publicintcalculateDiscount(booleanisPremiumMember,inttotalAmount){ intdiscount; if(isPremiumMember){ //Calculatediscountforpremiummembers discount=(totalAmount*PREMIUM_DISCOUNT_PERCENTAGE)/100; }else{ //Calculatediscountforregularmembers discount=(totalAmount*REGULAR_DISCOUNT_PERCENTAGE)/100; } returndiscount; } }
除了 if-else 構(gòu)造外,您還可以切換布爾方法形參 isPremiumMember 的值,而無需定義局部變量 discount,具體如下所示:
publicintcalculateDiscount(booleanisPremiumMember,inttotalAmount){ returnswitch(isPremiumMember){ casetrue->(totalAmount*PREMIUM_DISCOUNT_PERCENTAGE)/100; casefalse->(totalAmount*REGULAR_DISCOUNT_PERCENTAGE)/100; }; }
由于方法 calculateDiscount() 中的 switch 表達式為詳盡,如果您缺少 true 或 false 值中的任何一個,IntelliJ IDEA 都可以檢測到并建議您插入默認或缺少的 true/false case,如以下 gif 中所示:
將基元類型與 instanceof 運算符配合使用
在 Java 23 之前,任何基元類型都不能與 instanceof 運算符結(jié)合使用。
instanceof 運算符可用于檢查變量的類型,并有條件地執(zhí)行代碼。利用 instanceof 的模式匹配,如果待比較變量的類型與類型模式匹配,您還可以聲明和初始化模式變量,而無需顯式轉(zhuǎn)換。instanceof 變量還可以使用保護模式。
隨著將基元類型添加到 instanceof 運算符,您可以定義如下代碼:
importstaticjava.io.IO.println; voidmain(){ varweight=68; if(weightinstanceofbytebyteWeight&&byteWeight<=?70)?{ ????????println("Weight?less?than?70"); ????} }
請注意,Java 23 中的“隱式聲明的類與實例 main 方法”功能定義了具有 static 方法的 java.io.IO,允許您導入并使用 println() 將值輸出到控制臺,而不是使用 System.out.println() 執(zhí)行此操作。
如果您計劃檢查更多的類型和條件,可以使用帶有保護的 switch 構(gòu)造,具體如下所示:
varweight=68; switch(weight){ casebytebwhenbprintln("byte:lessthan70"); caseintiwheniprintln("int:lessthan7000"); caselonglwhenl>=7_000&&lprintln("longrange:7_000-70_000"); casedoubled->println("double"); }
數(shù)據(jù)類型之間的安全轉(zhuǎn)換
當您將模式匹配與基元數(shù)據(jù)類型配合使用時,Java 編譯器確保沒有信息丟失。在以下示例中,instanceof 運算符可以在檢測到安全時在 double 和 byte 數(shù)據(jù)類型之間轉(zhuǎn)換:
doubleheight=67; if(heightinstanceofbytebyteHeight) System.out.println(byteHeight);
如果沒有 instanceof 運算符,類似的代碼將無法執(zhí)行。以下代碼不會編譯:
doubleheight=67; finalbyteconvertToByte=height;
IntelliJ IDEA 中的穩(wěn)健數(shù)據(jù)流分析
IntelliJ IDEA 為 switch 語句中的基元類型提供了有力支持,還集成了復(fù)雜的數(shù)據(jù)流分析,可以幫助開發(fā)者避免常見問題。如以下示例中所示,IntelliJ IDEA 中的數(shù)據(jù)流分析可以確定第二個 case 標簽,即 case int _ 和其余的 case 標簽不可達(因為如果變量 weight 的值大于 70,代碼會退出方法)。IntelliJ IDEA 會就不可到達的代碼發(fā)出警告并提供適當?shù)慕ㄗh:
記錄和基元數(shù)據(jù)類型組件
想象一下,您定義了如下記錄 Person:
recordPerson(Stringname,doubleweight){}
在此之前,您可以將其分解為精確的數(shù)據(jù)類型。不過,借助模式匹配中的基元類型,您可以使用其他兼容的數(shù)據(jù)類型,例如 int、long 等。示例如下:
Personperson=newPerson("Java",672); switch(person){ casePerson(Stringname,byteweight)->println("byte:"+weight); casePerson(Stringname,intweight)->println("int:"+weight); casePerson(Stringname,doubleweight)->println("double:"+weight); casePerson(Stringname,longweight)->println("long:"+weight); default->thrownewIllegalStateException("Unexpectedvalue:"+person); }
您也可以將它與 instanceof 運算符配合使用,具體如下所示:
if(personinstanceofPerson(Stringname,byteweight)){ System.out.println("Instanceof:"+weight); }
IntelliJ IDEA 支持此功能的后續(xù)計劃
對模式匹配中基元數(shù)據(jù)類型的更多支持正在開發(fā),包括能夠在所有基元數(shù)據(jù)類型上使用后綴運算符 .switch 來開始編寫 switch 構(gòu)造。此外,也在開發(fā)的支持是將現(xiàn)有的 if-else 語句轉(zhuǎn)換為使用基元數(shù)據(jù)類型的 switch 構(gòu)造 – 這可讓您更輕松地采用此新功能。
Markdown 文檔注釋
(正式功能)
在此之前,Java 文檔注釋需要使用 HTML 和 JavaDoc 標記進行編寫。借助此新功能,即文檔注釋,您還可以使用 Markdown 編寫 JavaDoc 注釋。這是 Java 23 中的一項正式功能。
您是否想知道此更改的原因是什么?
原因之一是 HTML 不再是新開發(fā)者的流行選擇(盡管在 Java 于 20 世紀 90 年代后期推出時,它是一個不錯的選擇)。手動編寫 HTML 并不簡單。此外,Markdown 更易于編寫、閱讀,并且可以輕松轉(zhuǎn)換為 HTML。許多開發(fā)者都在使用 Markdown 來記錄他們的代碼、撰寫書籍、文章、博文,以及生成網(wǎng)站頁面等。
讓我們看看如何在您的源代碼文件中使用 Markdown 編寫 Javadoc 注釋,以及 IntelliJ IDEA 如何提供幫助。
一個示例
Markdown 文檔注釋以 /// 開頭。
使用三個斜杠的選擇非常有趣。Oracle 中此功能的負責人 Jonathan Gibbons 分享說,更改 Java 語言中功能的語法并非易事。多行注釋以 /* 開頭,以 */ 結(jié)尾。這樣便很難在文檔中包括可能包含 */ 的任何代碼。因此,Markdown 文檔注釋以 /// 開頭。
此外,也支持編寫文檔注釋的舊方法,即 HTML 和 JavaDoc 標記。Jonathan 還提到,無法將 JavaDoc 標記轉(zhuǎn)換為 Markdown 等效標記。因此,開發(fā)者可以使用 Markdown 注釋和 JavaDoc 標記的組合,以獲得兩全其美的結(jié)果。
下面是一個使用 Markdown 和 Javadoc 標記記錄方法的示例:
/// ///**GettingstartedandhavingfunlearningJava:)** /// ///Printsapatternoftheletter'P'usingthespecifiedcharacter. /// ///@paramsizethesizeofthepattern ///@paramcharToPrintthecharactertouseforthepattern /// privatevoidprintP(intsize,charcharToPrint){ for(inti=0;i
IntelliJ IDEA 可以幫助您在編輯器中切換視圖,查看文檔注釋對任何閱讀 Java 文檔注釋的人如何顯示。
在 IntelliJ IDEA 中查看 Java 文檔注釋
JEP“Markdown 文檔注釋”的負責人 Jonathan Gibbons 強調(diào),所有開發(fā)者都需要檢查他們添加到代碼庫中的 Java 文檔注釋是否正確。
IntelliJ IDEA 提供了“閱讀器模式”,讓您能夠在源代碼中查看 Java 文檔注釋。您還可以使用 Toggle Rendered View(切換渲染視圖)功能在 Java 文檔注釋代碼和查看方式之間切換,如以下 gif 中所示:
在 IntelliJ IDEA 中編寫
Markdown 文檔注釋
IntelliJ IDEA 可以檢測到您正在使用 Markdown 記錄方法。當您以 /// 開始并按 Enter 時,它也會在下一行添加 ///,如以下 GIF 中所示:
您是否應(yīng)該將現(xiàn)有的文檔注釋
轉(zhuǎn)換為使用 Markdown?
下面的 gif 顯示了在 IntelliJ IDEA 中使用 Markdown 編寫的 hashCode 方法的文檔。利用 Toggle Rendered View(切換渲染視圖),您可以輕松在閱讀器視圖中查看文檔,這更容易閱讀和理解。
理想情況下,除非您的開發(fā)者或 API 用戶在使用不提供替代視圖的工具(如 IntelliJ IDEA)查看您的(API、庫、框架)代碼庫時遇到重大可讀性問題,否則我不鼓勵您將現(xiàn)有文檔轉(zhuǎn)換為使用 Markdown。
模塊導入聲明(預(yù)覽功能)
借助此功能,您可以在類或接口中使用單條語句導入模塊庫(如 Java API),例如 import module java.base,這條語句將導入由模塊 java.base 導出的所有軟件包。
您不需要單獨的 import 語句來導入類中的軟件包,如 java.util,或者說 java.io,因為它們由 java.base 導出。
一個示例
以下代碼示例使用了來自 java.io 和 java.util 軟件包的類。通過包含語句 ‘import java.base’,您不需要單獨導入 java.io 和 java.util 軟件包,因為它們由模塊 java.base 導出:
importmodulejava.base; publicclassImportModuleHelloWorld{ publicstaticvoidmain(String[]args){ try{ InputStreaminputStream=newBufferedInputStream( newFileInputStream( newFile("abc.txt"))); }catch(FileNotFoundExceptione){ thrownewRuntimeException(e); } Maplist=newHashMap(); } }
不過,如果您從頂部刪除 import module 語句,則 IntelliJ IDEA 將從 java.io 和 java.util 軟件包中導入單個類和接口。此操作在以下 GIF 中顯示:
哪些軟件包是由模塊 java.base
(或其他模塊)導出的?
當您使用 IntelliJ IDEA 時,回答這個問題很簡單。點擊編輯器中的模塊名稱或使用相關(guān)快捷鍵(Go to Declaration(轉(zhuǎn)到聲明) 或 Go to Usages(轉(zhuǎn)到用法)),您可以查看此模塊的定義以找出由此模塊導出的所有模塊。此操作在以下 gif 中顯示:
隱式聲明的類與
實例 main 方法(第三預(yù)覽版)
此功能在 Java 21 中作為預(yù)覽語言功能引入,在 Java 23 中為第三個預(yù)覽版。
它將改變新 Java 開發(fā)者學習 Java 的方式。它簡化了學生學習基礎(chǔ)知識(例如變量賦值、序列、條件和迭代)時的初始步驟。學生不再需要聲明顯式類來開發(fā)代碼,或使用此簽名編寫其 main() 方法 public static void main(String [])。借助此功能,可以隱式聲明類,以及使用更短的關(guān)鍵字列表創(chuàng)建 main() 方法。
如果您不熟悉此功能,我強烈建議閱讀詳細介紹此功能的文章 ‘HelloWorld’ and ‘main()’ meet minimalistic。在本節(jié)中,我將包括 Java 23 中對此功能的補充。
使用模塊 java.base 導出的軟件包
而不顯式導入它們
只需在隱式類的頂部包含一條 import 語句,即 import module java.base,您就能自動導入 java.base 導出的軟件包。這意味著您的隱式類將不再需要這些類或軟件包的單獨 import 語句,如以下 gif 中所示:
簡化與控制臺交互的代碼的編寫
與控制臺交互 – 打印消息或使用消息是新 Java 開發(fā)者經(jīng)常使用的操作之一。在此功能中,這一點得到了進一步簡化。
您的隱式聲明的類可以使用方法 println() 和 print() 將消息輸出到控制臺,并使用方法 readln() 讀取字符串消息,而無需在您的類中顯式導入它們。所有這些方法都在一個由隱式類隱式導入的新頂層類 java.io.IO 中聲明。
花點時間,看看您需要如何在常規(guī)類中顯式導入它們,如以下 GIF 中所示:
以下 gif 顯示了當您在隱式類中使用前述相同方法時不需要顯式導入:
靈活的構(gòu)造函數(shù)體
(第二預(yù)覽版)
這是 JDK 22 中一項功能的第二預(yù)覽版,之前稱為“super() 之前的語句”。除了功能名稱的更改外,這項功能還有一個重要變化?,F(xiàn)在,可以在調(diào)用 super() 或 this() 之前初始化字段。
當超類從其構(gòu)造函數(shù)中調(diào)用方法,而您想要在子類中重寫此方法并在此方法內(nèi)部訪問子類中的字段時,這非常有用。此前,從超類構(gòu)造函數(shù)中調(diào)用方法時,子類字段不會初始化?,F(xiàn)在,可以初始化字段并防止意外。下面是展示此功能的示例代碼:
abstractclassAction{ publicAction(){ System.out.println("performing"+getText()); } publicabstractStringgetText(); } classDoubleActionextendsAction{ privatefinalStringtext; privateDoubleAction(Stringtext){ this.text=text;//thisdidnotcompilebeforeJava23withpreviewfeaturesenabled. super(); } @OverridepublicStringgetText(){ returntext+text; } }
如果您不熟悉此功能,敬請閱讀詳細介紹此功能的博文 https://blog.jetbrains.com/idea/2024/02/constructor-makeover-in-java-22/,其中探討了此功能的使用原因和使用方式。
預(yù)覽功能
在這篇博文中介紹的功能中,“模式、instanceof 和 switch 中的基元類型”、“模塊導入聲明”、“隱式聲明的類和實例 main 方法”和“靈活的構(gòu)造函數(shù)體”在 Java 23 中是預(yù)覽語言功能。Java 的新發(fā)布周期為六個月,新語言功能作為預(yù)覽功能發(fā)布。它們可能會在后續(xù) Java 版本的第二個或其他預(yù)覽版中重新引入,可能有也可能沒有更改。足夠穩(wěn)定后,它們就會作為標準語言功能添加到 Java 中。
預(yù)覽語言功能是完整的但不是永久的,這實際上意味著功能已經(jīng)準備好供開發(fā)者使用,只是更細致的細節(jié)可能會在未來的 Java 版本中根據(jù)開發(fā)者反饋發(fā)生變化。與 API 不同,語言功能在未來不能被棄用。因此,如果您對預(yù)覽語言功能有任何反饋,請隨時在 JDK 郵件名單(需要免費注冊)中分享。
由于這些功能的運作方式,IntelliJ IDEA 僅支持當前 JDK 的預(yù)覽功能。預(yù)覽語言功能在不同 Java 版本間可能發(fā)生變化,直到它們被移除或添加為標準語言功能。使用舊版本 Java SE Platform 中的預(yù)覽語言功能的代碼可能無法在新版本上編譯或運行。
總結(jié)
在這篇博文中,我介紹了五個 Java 23 功能 – 模式、instanceof 和 switch 中的基元類型、Markdown 文檔注釋、模塊導入聲明、隱式聲明的類與實例 main 方法,以及靈活的構(gòu)造函數(shù)體。
查看這些新功能,了解它們?nèi)绾螏椭倪M應(yīng)用程序。
-
JAVA
+關(guān)注
關(guān)注
19文章
2966瀏覽量
104700 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4327瀏覽量
62569 -
MarkDown
+關(guān)注
關(guān)注
0文章
46瀏覽量
262
原文標題:Java 23和IntelliJ IDEA
文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論