Java?17新特性詳細(xì)講解與代碼實(shí)例
前言
Java 17是Java SE 17的開(kāi)源參考實(shí)現(xiàn),于2021年9月14日正式發(fā)布,是Java 11以來(lái)的又一個(gè)長(zhǎng)期支持(LTS)版本。Java 17中有一些新的特性和改進(jìn),本文將對(duì)它們進(jìn)行簡(jiǎn)要的介紹和示例。
密封類
密封類和接口限制了哪些其他類或接口可以擴(kuò)展或?qū)崿F(xiàn)它們,增強(qiáng)了封裝性和可維護(hù)性。密封類由JEP 360并在JDK 15中作為預(yù)覽功能交付。它們?cè)俅伪惶岢?,并進(jìn)行了改進(jìn),由JEP 397并在JDK 16中作為預(yù)覽功能提供?,F(xiàn)在,在JDK 17中,密封類正在最終確定,與JDK 16沒(méi)有任何更改。
要定義一個(gè)密封類或接口,需要使用sealed
修飾符,并且在聲明中指定允許擴(kuò)展或?qū)崿F(xiàn)它的其他類或接口。這些類或接口被稱為子類或子接口。子類或子接口可以使用final
修飾符來(lái)表示它們不能被進(jìn)一步擴(kuò)展或?qū)崿F(xiàn),或者使用sealed
修飾符來(lái)表示它們也是密封的,并且需要指定它們的子類或子接口,或者使用non-sealed
修飾符來(lái)表示它們不是密封的,并且可以被任意的類或接口擴(kuò)展或?qū)崿F(xiàn)。
例如,我們可以定義一個(gè)密封的形狀接口Shape,并且指定它只能被Circle、Rectangle和Triangle這三個(gè)類實(shí)現(xiàn):
public sealed interface Shape permits Circle, Rectangle, Triangle { double area(); }
然后,我們可以定義這三個(gè)類,并且分別使用final
、sealed
和non-sealed
修飾符:
public final class Circle implements Shape { private final double radius; public Circle(double radius) { this.radius = radius; } public double area() { return Math.PI * radius * radius; } } public sealed class Rectangle implements Shape permits Square { private final double length; private final double width; public Rectangle(double length, double width) { this.length = length; this.width = width; } public double area() { return length * width; } } public non-sealed class Triangle implements Shape { private final double base; private final double height; public Triangle(double base, double height) { this.base = base; this.height = height; } public double area() { return base * height / 2; } }
注意,Square是Rectangle的子類,并且也是密封的:
public final class Square extends Rectangle { public Square(double side) { super(side, side); } }
這樣,我們就可以保證Shape接口只能被這四個(gè)類實(shí)現(xiàn),而不會(huì)有其他的可能性。我們也可以使用模式匹配來(lái)對(duì)不同的形狀進(jìn)行操作,例如:
public static void printArea(Shape shape) { if (shape instanceof Circle c) { System.out.println("The area of the circle is " + c.area()); } else if (shape instanceof Rectangle r) { System.out.println("The area of the rectangle is " + r.area()); } else if (shape instanceof Triangle t) { System.out.println("The area of the triangle is " + t.area()); } }
switch表達(dá)式
switch表達(dá)式允許switch有返回值,并且可以直接作為結(jié)果賦值給一個(gè)變量,簡(jiǎn)化了多分支的邏輯。switch表達(dá)式由JEP 325并在JDK 12中作為預(yù)覽功能交付。它們?cè)俅伪惶岢觯⑦M(jìn)行了改進(jìn),由JEP 354并在JDK 13中作為預(yù)覽功能提供。它們?cè)俅伪惶岢?,并進(jìn)行了改進(jìn),由JEP 361并在JDK 14中作為預(yù)覽功能提供?,F(xiàn)在,在JDK 17中,switch表達(dá)式正在最終確定,與JDK 14沒(méi)有任何更改。
要定義一個(gè)switch表達(dá)式,需要使用->
符號(hào)來(lái)表示每個(gè)分支的結(jié)果,并且在表達(dá)式的末尾加上一個(gè)分號(hào)。例如,我們可以定義一個(gè)根據(jù)月份返回季節(jié)的switch表達(dá)式:
public static String getSeason(int month) { return switch (month) { case 12, 1, 2 -> "Winter"; case 3, 4, 5 -> "Spring"; case 6, 7, 8 -> "Summer"; case 9, 10, 11 -> "Autumn"; default -> "Unknown"; }; }
注意,我們可以使用逗號(hào)來(lái)分隔多個(gè)匹配值,也可以使用default來(lái)表示其他情況。我們也可以使用yield關(guān)鍵字來(lái)返回一個(gè)值,這在需要在返回之前進(jìn)行一些操作的情況下很有用,例如:
public static String getSeason(int month) { return switch (month) { case 12, 1, 2 -> { System.out.println("It's cold!"); yield "Winter"; } case 3, 4, 5 -> { System.out.println("It's warm!"); yield "Spring"; } case 6, 7, 8 -> { System.out.println("It's hot!"); yield "Summer"; } case 9, 10, 11 -> { System.out.println("It's cool!"); yield "Autumn"; } default -> { System.out.println("It's unknown!"); yield "Unknown"; } }; }
文本塊
文本塊允許使用三個(gè)雙引號(hào)來(lái)定義一個(gè)多行的字符串,避免了轉(zhuǎn)義和拼接的麻煩。文本塊由JEP
355并在JDK 13中作為預(yù)覽功能交付。它們?cè)俅伪惶岢?,并進(jìn)行了改進(jìn),由JEP 368并在JDK 14中作為預(yù)覽功能提供。它們?cè)俅伪惶岢?,并進(jìn)行了改進(jìn),由JEP 378并在JDK 15中作為預(yù)覽功能提供。現(xiàn)在,在JDK 17中,文本塊正在最終確定,與JDK 15沒(méi)有任何更改。
要定義一個(gè)文本塊,需要使用三個(gè)雙引號(hào)"""
來(lái)開(kāi)始和結(jié)束,并且結(jié)束的三個(gè)雙引號(hào)不能和開(kāi)始的在同一行。例如,我們可以定義一個(gè)包含JSON數(shù)據(jù)的文本塊:
public static String getJson() { return """ { "name": "Java", "version": 17, "features": [ "sealed classes", "switch expressions", "text blocks" ] } """; }
注意,文本塊中的換行符會(huì)被保留,而不需要使用\n
來(lái)表示。我們也可以使用\
來(lái)表示忽略換行符,或者使用\s
來(lái)表示一個(gè)空格。例如:
public static String getGreeting() { return """ Hello,\ World! """; } public static String getPoem() { return """ Twinkle, twinkle, little star,\s How I wonder what you are.\s Up above the world so high,\s Like a diamond in the sky. """; }
模式匹配
模式匹配允許在instanceof和switch中使用模式來(lái)測(cè)試表達(dá)式的類型和結(jié)構(gòu),提高了代碼的可讀性和靈活性。模式匹配由JEP 305并在JDK 14中作為預(yù)覽功能交付。它們?cè)俅伪惶岢?,并進(jìn)行了改進(jìn),由JEP 375并在JDK 15中作為預(yù)覽功能提供。它們?cè)俅伪惶岢?,并進(jìn)行了改進(jìn),由JEP 394并在JDK 16中作為預(yù)覽功能提供?,F(xiàn)在,在JDK 17中,模式匹配正在最終確定,與JDK 16沒(méi)有任何更改。
要使用模式匹配,需要使用instanceof
或switch
關(guān)鍵字,并且在測(cè)試的類型后面加上一個(gè)變量名,用于綁定匹配的值。例如,我們可以使用模式匹配來(lái)判斷一個(gè)對(duì)象是否是字符串,并且獲取它的長(zhǎng)度:
public static void printLength(Object obj) { if (obj instanceof String s) { System.out.println("The length of the string is " + s.length()); } else { System.out.println("The object is not a string"); } }
注意,我們不需要再進(jìn)行強(qiáng)制類型轉(zhuǎn)換,因?yàn)樽兞?code>s已經(jīng)被綁定為字符串類型。我們也可以使用模式匹配來(lái)判斷一個(gè)對(duì)象是否是密封類的子類,并且獲取它的屬性:
public static void printShape(Shape shape) { switch (shape) { case Circle c -> System.out.println("The radius of the circle is " + c.radius()); case Rectangle r -> System.out.println("The area of the rectangle is " + r.area()); case Triangle t -> System.out.println("The base of the triangle is " + t.base()); default -> System.out.println("Unknown shape"); } }
注意,我們不需要再進(jìn)行類型檢查或者類型轉(zhuǎn)換,因?yàn)樽兞?code>c、r
和t
已經(jīng)被綁定為相應(yīng)的類型。
增強(qiáng)型偽隨機(jī)數(shù)生成器
增強(qiáng)型偽隨機(jī)數(shù)生成器為PRNG提供了新的接口類型和實(shí)現(xiàn),包括可跳轉(zhuǎn)的PRNG和一類額外的可拆分PRNG算法(LXM)。增強(qiáng)型偽隨機(jī)數(shù)生成器由JEP 356并在JDK 17中作為正式功能提供。
要使用增強(qiáng)型偽隨機(jī)數(shù)生成器,需要使用java.util.random
包中的新的接口和類。例如,我們可以使用RandomGenerator
接口來(lái)獲取一個(gè)PRNG的實(shí)例,并且使用它來(lái)生成各種類型的隨機(jī)數(shù):
public static void generateRandomNumbers() { RandomGenerator random = RandomGenerator.getDefault(); System.out.println("A random boolean: " + random.nextBoolean()); System.out.println("A random int: " + random.nextInt()); System.out.println("A random long: " + random.nextLong()); System.out.println("A random float: " + random.nextFloat()); System.out.println("A random double: " + random.nextDouble()); }
注意,RandomGenerator
接口提供了很多方便的方法來(lái)生成不同范圍和分布的隨機(jī)數(shù),例如nextInt(int bound)
、nextLong(long bound)
、nextGaussian()
等。我們也可以使用RandomGeneratorFactory
類來(lái)獲取不同的PRNG算法的實(shí)例,例如:
public static void useDifferentAlgorithms() { RandomGenerator random1 = RandomGeneratorFactory.of("L32X64MixRandom"); RandomGenerator random2 = RandomGeneratorFactory.of("L64X128MixRandom"); RandomGenerator random3 = RandomGeneratorFactory.of("L128X256MixRandom"); System.out.println("Using L32X64MixRandom: " + random1.nextInt()); System.out.println("Using L64X128MixRandom: " + random2.nextInt()); System.out.println("Using L128X256MixRandom: " + random3.nextInt()); }
注意,RandomGeneratorFactory
類提供了很多方法來(lái)獲取或者查詢不同的PRNG算法,例如of(String name)
、all()
、preferred()
等。我們也可以使用JumpableRandomGenerator
接口或者SplittableRandomGenerator
接口來(lái)獲取一個(gè)可跳轉(zhuǎn)或者可拆分的PRNG實(shí)例,并且使用它們來(lái)生成不同的子生成器,例如:
public static void useJumpableOrSplittableGenerators() { JumpableRandomGenerator jumpable = RandomGeneratorFactory.jumpable(); SplittableRandomGenerator splittable = RandomGeneratorFactory.splittable(); System.out.println("Using the original jumpable generator: " + jumpable.nextInt()); System.out.println("Using the original splittable generator: " + splittable.nextInt()); JumpableRandomGenerator jumped = jumpable.jump(); SplittableRandomGenerator splitted = splittable.split(); System.out.println("Using the jumped generator: " + jumped.nextInt()); System.out.println("Using the splitted generator: " + splitted.nextInt()); }
注意,JumpableRandomGenerator
接口和SplittableRandomGenerator
接口都繼承自RandomGenerator
接口,并且提供了額外的方法來(lái)生成子生成器,例如jump()
、split()
等。這些子生成器可以用于并行計(jì)算或者其他場(chǎng)景。
新的macOS渲染管道
新的macOS渲染管道使用Apple Metal加速渲染API來(lái)替代被Apple棄用的OpenGL API。新的macOS渲染管道由JEP 382并在JDK 17中作為正式功能提供。
要使用新的macOS渲染管道,需要在運(yùn)行Java程序時(shí)設(shè)置系統(tǒng)屬性:
-Dsun.java2d.metal=true
這樣,Java 2D API和Swing API用于渲染的Java 2D API就可以使用Metal API來(lái)加速渲染。這對(duì)于Java程序是透明的,因?yàn)檫@是內(nèi)部實(shí)現(xiàn)的區(qū)別,對(duì)Java API沒(méi)有影響。Metal管道需要macOS 10.14.x或更高版本。在早期版本上設(shè)置它的嘗試將被忽略。
總結(jié)
到此這篇關(guān)于Java 17新特性的文章就介紹到這了,更多相關(guān)Java17新特性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)的具有GUI的校園導(dǎo)航系統(tǒng)的完整代碼
這篇文章主要介紹了Java實(shí)現(xiàn)的具有GUI的校園導(dǎo)航系統(tǒng)的完整代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04OpenFeign調(diào)用服務(wù)請(qǐng)求頭丟失Token的解決
這篇文章主要介紹了OpenFeign調(diào)用服務(wù)請(qǐng)求頭丟失Token的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06springcloud之Feign、ribbon如何設(shè)置超時(shí)時(shí)間和重試機(jī)制
這篇文章主要介紹了springcloud之Feign、ribbon如何設(shè)置超時(shí)時(shí)間和重試機(jī)制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之二手書(shū)商城系統(tǒng)的實(shí)現(xiàn)
這是一個(gè)使用了java+JSP+Springboot+maven+mysql+ThymeLeaf+FTP開(kāi)發(fā)的二手書(shū)商城系統(tǒng),是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有在線書(shū)城該有的所有功能,感興趣的朋友快來(lái)看看吧2022-01-01java仿Servlet生成驗(yàn)證碼實(shí)例詳解
這篇文章主要介紹了java仿Servlet生成驗(yàn)證碼實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04使用try-with-resource的輸入輸出流自動(dòng)關(guān)閉
這篇文章主要介紹了使用try-with-resource的輸入輸出流自動(dòng)關(guān)閉方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07SpringMVC獲取HTTP中元素的實(shí)現(xiàn)示例
本文主要介紹了SpringMVC獲取HTTP中的元素,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-02-02SpringBoot實(shí)現(xiàn)websocket服務(wù)端及客戶端的詳細(xì)過(guò)程
文章介紹了WebSocket通信過(guò)程、服務(wù)端和客戶端的實(shí)現(xiàn),以及可能遇到的問(wèn)題及解決方案,感興趣的朋友一起看看吧2024-12-12Java?方法(方法的定義,可變參數(shù),參數(shù)的傳遞問(wèn)題,方法重載,方法簽名)
這篇文章主要介紹了Java?方法(方法的定義,可變參數(shù),參數(shù)的傳遞問(wèn)題,方法重載,方法簽名),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下2022-09-09