日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 17 新特性尝鲜

發布時間:2024/5/14 java 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 17 新特性尝鲜 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JDK 17更新了包括14個特性,具體如下表所示:

  • Restore Always-StrictFloating-Point Semantics?恢復始終嚴格模式(Always-Strict)的浮點語義
  • EnhancedPseudo-Random Number Generators? 增強型偽隨機數生成器
  • New macOS RenderingPipeline?新增macOS渲染管道
  • macOS/AArch64 Port?支持將JDK移植到macOS或AArch64
  • Deprecate the AppletAPI for Removal?棄用待移除的Applet API
注:JDK 9中的JEP 289先前已棄用Applet API,但并未將其刪除。
  • Strongly EncapsulateJDK Internals?強封裝JDK內部API
  • Pattern Matching forswitch (Preview)?switch模式匹配進入預覽(Preview)階段
  • Remove RMI Activation?移除RMI(遠程方法調用)激活機制
  • Sealed Classes?密封類
注:密封類是由JEP 360提出的,并在JDK 15中作為預覽功能提供。它們由JEP 397再次提出并進行了改進,并作為預覽功能在JDK 16中提供。該JEP建議在JDK17中完成密封類,與JDK 16沒有任何變化。
  • Remove theExperimental AOT and JIT Compiler?移除實驗性AOT和JIT編譯器
  • Deprecate theSecurity Manager for Removal?棄用待移除的安全管理器(Security Manager)
注:棄用安全管理器,在后續版本中移除。安全管理器可追溯到Java 1.0。多年來,它一直不是保護客戶端Java代碼的主要手段,也很少用于保護服務器端代碼。為了推動Java向前發展,Oracle打算棄用安全管理器,以便與舊Applet API(JEP 398)一起刪除。
  • Foreign Function& Memory API (Incubator)?外部函數和內存API(孵化器)孵化階段
注:Java程序可以通過該API與Java運行時之外的代碼和數據進行互操作。通過有效調用外部函數(即JVM之外的代碼),以及安全地訪問外部內存(即不由JVM管理的內存),API使Java程序能夠調用本地庫和處理本地數據,而沒有JNI。
  • Vector API (SecondIncubator)?Vector API(第二孵化器)第二孵化階段
注:引入一個API來表達向量計算,這些計算在運行時可靠地編譯為支持的CPU架構上的最佳向量指令,從而實現優于等效標量計算的性能。
  • Context-SpecificDeserialization Filters?上下文特定的反序列化過濾器
注:允許應用程序通過JVM范圍的過濾器工廠配置特定于上下文和動態選擇的反序列化過濾器,該工廠被調用以為每個單獨的反序列化操作選擇一個過濾器。[關于JDK17新特性開發應用,關注公眾號Java精選,后續文章更新]

至于Spring,其官方曾宣布Spring Framework 6.0和Spring Boot 3.0將基于JDK 17版本,預計2022年,下半年 發布 Spring Framework 6.0正式候選(RC)版本。

代碼層面

  • 文本塊

  • switch表達式

  • record關鍵字

  • sealed classes密封類

  • instanceof模式匹配

  • Helpful NullPointerExceptions

  • 日期周期格式化

  • 精簡數字格式化支持

  • Stream.toList()簡化

文本塊

在Java17之前的版本里,定義一個字符串,比如一個JSON數據,基本都是如下拼接方式定義:

public void lowVersion() { String text = "{\n" + " \"name\": \"小黑說Java\",\n" + " \"age\": 18,\n" + " \"address\": \"北京市西城區\"\n" + "}"; System.out.println(text); }

通過Java 17中的類似的字符串處理則會方便很多;通過三個雙引號可以定義一個文本塊,并且結束的三個雙引號不能和開始的在同一行。文本塊語法代碼如下:

private void highVersion() {String text = """{"name":"小黑說Java", "age": 18, "address": "北京市西城區"}"""; System.out.println(text); }

這段代碼的輸出結果是:

{ "name": "小黑說Java", "age": 18, "address": "北京市西城區" }

switch表達式

Java 17版本中switch表達式將允許switch有返回值,并且可以直接作為結果賦值給一個變量,等等一系列的變化。

下面有一個switch例子,依賴于給定的枚舉值,執行case操作,故意省略break。

private static void lowVesion(Fruit fruit) { switch (fruit) { case APPLE, PEAR: System.out.println("普通水果");break;case MANGO, AVOCADO: System.out.println("進口水果"); break;default: System.out.println("未知水果"); } }

調用這個方法傳入一個APPLE,會輸出以下結果:

普通水果 進口水果 未知水果

通過switch表達式來進行簡化。將冒號(:)替換為箭頭(->),并且switch表達式默認不會失敗,所以不需要break。

private static void withSwitchExpression(Fruit fruit) { switch (fruit) { case APPLE, PEAR -> System.out.println("普通水果"); case MANGO, AVOCADO -> System.out.println("進口水果"); default -> System.out.println("未知水果"); } }

switch表達式也可以返回一個值,比如上面的例子可以讓switch返回一個字符串來表示要打印的文本。需要注意在switch語句的最后要加一個分號。

private static void withReturnValue(Fruit fruit) { String text = switch (fruit) { case APPLE, PEAR -> "普通水果"; case MANGO, AVOCADO -> "進口水果"; default -> "未知水果"; }; System.out.println(text); }

也可以直接省略賦值動作直接打印。

private static void withReturnValue(Fruit fruit) { System.out.println(switch (fruit) { case APPLE, PEAR -> "普通水果"; case MANGO, AVOCADO -> "進口水果"; default -> "未知水果"; }); }

如果想在case里想做不止一件事,比如在返回之前先進行一些計算或者打印操作,可以通過大括號來作為case塊,最后的返回值使用關鍵字yield進行返回。

private static void withYield(Fruit fruit) { String text = switch (fruit) { case APPLE, PEAR -> { System.out.println("給的水果是: " + fruit); yield "普通水果";} case MANGO, AVOCADO -> "進口水果";default -> "未知水果"; }; System.out.println(text); }

這個輸出結果是:

給的水果是: APPLE 普通水果

也可以直接使用yield返回結果。

private static void oldStyleWithYield(Fruit fruit) { System.out.println(switch (fruit) {case APPLE, PEAR: yield "普通水果"; case MANGO, AVOCADO: yield "進口水果"; default: yield "未知水果"; }); }

record關鍵字

record用于創建不可變的數據類。在這之前如果需要創建一個存放數據的類,通常需要先創建一個Class,然后生成構造方法、getter、setter、hashCode、equals和toString等這些方法,或者使用Lombok來簡化這些操作。

比如定義一個Person類:

//這里使用lombok減少代碼 @Data @AllArgsConstructor public class Person {private String name; private int age; private String address; }

通過Person類做一些測試,比如創建兩個對象,對他們進行比較,打印這些操作。

public static void testPerson() { Person p1 = new Person("小黑說Java", 18, "北京市西城區"); Person p2 = new Person("小白說Java", 28, "北京市東城區"); System.out.println(p1); System.out.println(p2); System.out.println(p1.equals(p2)); }

假設有一些場景只需要對Person的name和age屬性進行打印,在有record之后將會變得非常容易。

public static void testPerson() { Person p1 = new Person("小黑說Java", 18, "北京市西城區"); Person p2 = new Person("小白說Java", 28, "北京市東城區"); // 使用record定義 record PersonRecord(String name,int age){} PersonRecord p1Record = new PersonRecord(p1.getName(), p1.getAge()); PersonRecord p2Record = new PersonRecord(p2.getName(), p2.getAge()); System.out.println(p1Record); System.out.println(p2Record); }

record也可以單獨定義作為一個文件定義,但是因為Record的使用非常緊湊,所以可以直接在需要使用的地方直接定義。

public record PersonRecord(String name, int age){}

record同樣也有構造方法,可以在構造方法中對數據進行一些驗證操作。

public static void testPerson() { Person p1 = new Person("小黑說Java", 18, "北京市西城區"); Person p2 = new Person(null, 28, "北京市東城區"); record PersonRecord(String name, int age) { // 構造方法 PersonRecord { System.out.println("name " + name + " age " + age); if (name == null) { throw new IllegalArgumentException("姓名不能為空");} } } PersonRecord p1Record = new PersonRecord(p1.getName(), p1.getAge()); PersonRecord p2Record = new PersonRecord(p2.getName(), p2.getAge()); }

密封類 sealed class

密封類可以讓更好的控制哪些類可以對定義的類進行擴展。密封類可能對于框架或中間件的開發者更有用。在這之前一個類要么是可以被extends的,要么是final的,只有這兩種選項。

密封類可以控制有哪些類可以對超類進行繼承,在Java 17之前如果需要控制哪些類可以繼承,可以通過改變類的訪問級別,比如去掉類的public,訪問級別為。比默認如在com.everlight.java11包中定義了如下的三個類:

package com.everlight.java11; public abstract class Furit { } public class Apple extends Furit { } public class Pear extends Furit { }

那么可以在另一個包com.everlight.java11中寫如下的代碼:

private static void test() { Apple apple = new Apple(); Pear pear = new Pear(); Fruit fruit = apple; class Avocado extends Fruit {}; }

既可以定義Apple,Pear,也可以將apple實例賦值給Fruit,并且可以對Fruit進行繼承。

如果不想讓Fruit在com.everlight.java11包以外被擴展,在Java11版本中只能改變訪問權限,去掉class的public修飾符。這樣雖然可以控制被被繼承,但是也會導致Fruit fruit = apple;也編譯失敗;在Java 17中通過密封類可以解決這個問題。

package com.everlight.java17; public abstract sealed class Furit permits Apple,Pear { } public non-sealed class Apple extends Furit { } public final class Pear extends Furit { }

在定義Furit時通過關鍵字sealed聲明為密封類,通過permits可以指定Apple,Pear類可以進行繼承擴展。

子類需要指明它是final,non-sealed或sealed的。父類不能控制子類是否可以被繼承。

private static void test() { Apple apple = new Apple(); Pear pear = new Pear(); // 可以將apple賦值給Fruit Fruit fruit = apple; // 只能繼承Apple,不能繼承Furit class Avocado extends Apple {}; }

instanceof模式匹配

通常使用instanceof時,一般發生在需要對一個變量的類型進行判斷,如果符合指定的類型,則強制類型轉換為一個新變量。

private static void oldStyle(Object o) { if (o instanceof Furit) { Furit furit = (GrapeClass) o; System.out.println("This furit is :" + furit.getName); } }

在使用instanceof的模式匹配后,上面的代碼可進行簡寫。

private static void oldStyle(Object o) { if (o instanceof Furit furit) { System.out.println("This furit is :" + furit.getName); } }

可以將類型轉換和變量聲明都在if中處理。同時,可以直接在if中使用這個變量。

private static void oldStyle(Object o) { if (o instanceof Furit furit && furit.getColor()==Color.RED) { System.out.println("This furit is :" + furit.getName); } }

因為只有當instanceof的結果為true時,才會定義變量furit,所以這里可以使用&&,但是改為||就會編譯報錯。

Helpful NullPointerExceptions

Helpful NullPointerExceptions可以在遇到NPE時節省一些分析時間。如下的代碼會導致一個NPE。

public static void main(String[] args) { Person p = new Person(); String cityName = p.getAddress().getCity().getName(); }

在Java 11中,輸出將顯示NullPointerException發生的行號,但不知道哪個方法調用時產生的null,必須通過調試的方式找到。

Exception in thread "main" java.lang.NullPointerException at com.everlight.java17.HelpfulNullPointerExceptionsDemo.main(HelpfulNullPointerExceptionsDemo.java :13)

在Java 17中,則會準確顯示發生NPE的精確位置。

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.everlight.java17.Address.getCity()" because the return value of "com.everlight.java17.Person.getAddress()" is null at com.everlight.java17.HelpfulNullPointerExceptionsDemo.main(HelpfulNullPointerExceptionsDemo.java :13)

日期周期格式化

在Java 17中添加了一個新的模式B,用于格式化DateTime,它根據Unicode標準指示一天時間段。

使用默認的英語語言環境,打印一天的幾個時刻:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("B"); System.out.println(dtf.format(LocalTime.of(8, 0))); System.out.println(dtf.format(LocalTime.of(13, 0))); System.out.println(dtf.format(LocalTime.of(20, 0))); System.out.println(dtf.format(LocalTime.of(23, 0))); System.out.println(dtf.format(LocalTime.of(0, 0)));

輸出結果:

in the morning in the afternoon in the evening at night midnight

如果是中文語言環境,則輸出結果為:

上午 下午 晚上 晚上 午夜

可見java17的晚上是包括英美國家的evening和night的。

精簡數字格式化支持

在NumberFormat中添加了一個工廠方法,可以根據Unicode標準以緊湊的、人類可讀的形式格式化數字。

short格式如下所示:

NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.SHORT); System.out.println(fmt.format(1000)); System.out.println(fmt.format(100000)); System.out.println(fmt.format(1000000));

輸出格式為:

1K 100K 1M

long格式如下所示:

fmt = NumberFormat.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG); System.out.println(fmt.format(1000)); System.out.println(fmt.format(100000)); System.out.println(fmt.format(1000000));

輸出結果為:

1 thousand 100 thousand 1 million

Stream.toList()

如果需要將Stream轉換成List,需要通過調用collect方法使用Collectors.toList(),代碼非常冗長。

private static void oldStyle() { Stream<String> stringStream = Stream.of("a", "b", "c"); List<String> stringList = stringStream.collect(Collectors.toList()); for(String s : stringList) { System.out.println(s); } }

在Java 17中將會變得簡單,可以直接調用toList()。

private static void streamToList() { Stream<String> stringStream = Stream.of("a", "b", "c");List<String> stringList = stringStream.toList();for(String s : stringList) { System.out.println(s); } }?

總結

以上是生活随笔為你收集整理的Java 17 新特性尝鲜的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。