<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 8 !Java 17&18 新特性真香

          共 22204字,需瀏覽 45分鐘

           ·

          2022-05-27 16:33

          來源于程序猿阿朗?,作者程序猿阿朗

          Hollis的新書限時(shí)折扣中,一本深入講解Java基礎(chǔ)的干貨筆記!

          Java 17

          img

          Java 17?在 2021 年 9 月 14 日正式發(fā)布,Java 17 是一個(gè)長(zhǎng)期支持(LTS)版本,這次更新共帶來 14 個(gè)新功能。

          OpenJDK Java 17 下載:https://jdk.java.net/archive/

          OpenJDK Java 17 文檔:https://openjdk.java.net/projects/jdk/17/

          JEP描述
          JEP 306恢復(fù)始終嚴(yán)格的浮點(diǎn)語義[1]
          JEP 356增強(qiáng)的偽隨機(jī)數(shù)生成器[2]
          JEP 382使用新的 macOS 渲染庫[3]
          JEP 391支持 macOS/AArch64 架構(gòu)[4]
          JEP 398刪除已啟用的 Applet API[5]
          JEP 403更強(qiáng)的封裝 JDK 內(nèi)部封裝[6]
          JEP 406Switch 模式匹配(預(yù)覽)[7]
          JEP 407移除 RMI Activation[8]
          JEP 409密封類(Sealed Classes)[9]
          JEP 410JEP 401:移除實(shí)驗(yàn)性的 AOT 和 JIT 編譯器[10]
          JEP 411棄用 Security Manager[11]
          JEP 412外部函數(shù)和內(nèi)存 API(孵化器)[12]
          JEP 414Vector API(第二孵化器)[13]
          JEP 415指定上下文的反序列化過濾器[14]

          JEP 306:恢復(fù)始終嚴(yán)格的浮點(diǎn)語義

          既然是恢復(fù)嚴(yán)格的浮點(diǎn)語義,那么說明在某個(gè)時(shí)間點(diǎn)之前,是始終嚴(yán)格的浮點(diǎn)語義的。其實(shí)在 Java SE 1.2 之前,所有的浮點(diǎn)計(jì)算都是嚴(yán)格的,但是以當(dāng)初的情況來看,過于嚴(yán)格的浮點(diǎn)計(jì)算在當(dāng)初流行的 x86 架構(gòu)和 x87 浮點(diǎn)協(xié)議處理器上運(yùn)行,需要大量的額外的指令開銷,所以在 Java SE 1.2 開始,需要手動(dòng)使用關(guān)鍵字?strictfp(strict float point) 才能啟用嚴(yán)格的浮點(diǎn)計(jì)算。

          但是在 2021 年的今天,硬件早已發(fā)生巨變,當(dāng)初的問題已經(jīng)不存在了,所以從 Java 17 開始,恢復(fù)了始終嚴(yán)格的浮點(diǎn)語義這一特性。

          擴(kuò)展strictfp?是 Java 中的一個(gè)關(guān)鍵字,大多數(shù)人可能沒有注意過它,它可以用在類、接口或者方法上,被 strictfp 修飾的部分中的 float 和 double 表達(dá)式會(huì)進(jìn)行嚴(yán)格浮點(diǎn)計(jì)算。

          下面是一個(gè)示例,其中的?testStrictfp()?被?strictfp?修飾。

          package?com.wdbyte;

          public?class?Main?{
          ????public?static?void?main(String[]?args)?{
          ????????testStrictfp();
          ????}

          ????public?strictfp?static?void?testStrictfp()?{
          ????????float?aFloat?=?0.6666666666666666666f;
          ????????double?aDouble?=?0.88888888888888888d;
          ????????double?sum?=?aFloat?+?aDouble;
          ????????System.out.println("sum:?"?+?sum);
          ????}
          }

          JEP 356:增強(qiáng)的偽隨機(jī)數(shù)生成器

          為偽隨機(jī)數(shù)生成器 RPNG(pseudorandom number generator)增加了新的接口類型和實(shí)現(xiàn),讓在代碼中使用各種 PRNG 算法變得容易許多。

          這次增加了?RandomGenerator?接口,為所有的 PRNG 算法提供統(tǒng)一的 API,并且可以獲取不同類型的 PRNG 對(duì)象流。同時(shí)也提供了一個(gè)新類?RandomGeneratorFactory?用于構(gòu)造各種?RandomGenerator?實(shí)例,在?RandomGeneratorFactory?中使用?ServiceLoader.provider?來加載各種 PRNG 實(shí)現(xiàn)。

          下面是一個(gè)使用示例:隨便選擇一個(gè) PRNG 算法生成 5 個(gè) 10 以內(nèi)的隨機(jī)數(shù)。

          package?com.wdbyte.java17;

          import?java.util.Date;
          import?java.util.random.RandomGenerator;
          import?java.util.random.RandomGeneratorFactory;
          import?java.util.stream.Stream;

          /**
          ?*?@author?niulang
          ?*/

          public?class?JEP356?{

          ????public?static?void?main(String[]?args)?{
          ????????RandomGeneratorFactory?l128X256MixRandom?=?RandomGeneratorFactory.of("L128X256MixRandom");
          ????????//?使用時(shí)間戳作為隨機(jī)數(shù)種子
          ????????RandomGenerator?randomGenerator?=?l128X256MixRandom.create(System.currentTimeMillis());
          ????????for?(int?i?=?0;?i?5;?i++)?{
          ????????????System.out.println(randomGenerator.nextInt(10));
          ????????}
          ????}
          }

          得到輸出:

          7
          3
          4
          4
          6

          你也可以遍歷出所有的 PRNG 算法。

          RandomGeneratorFactory.all().forEach(factory?->?{
          ????System.out.println(factory.group()?+?":"?+?factory.name());
          });

          得到輸出:

          LXM:L32X64MixRandom
          LXM:L128X128MixRandom
          LXM:L64X128MixRandom
          Legacy:SecureRandom
          LXM:L128X1024MixRandom
          LXM:L64X128StarStarRandom
          Xoshiro:Xoshiro256PlusPlus
          LXM:L64X256MixRandom
          Legacy:Random
          Xoroshiro:Xoroshiro128PlusPlus
          LXM:L128X256MixRandom
          Legacy:SplittableRandom
          LXM:L64X1024MixRandom

          可以看到?Legacy:Random?也在其中,新的 API 兼容了老的?Random?方式,所以你也可以使用新的 API 調(diào)用?Random?類生成隨機(jī)數(shù)。

          //?使用?Random
          RandomGeneratorFactory?l128X256MixRandom?=?RandomGeneratorFactory.of("Random");
          //?使用時(shí)間戳作為隨機(jī)數(shù)種子
          RandomGenerator?randomGenerator?=?l128X256MixRandom.create(System.currentTimeMillis());
          for?(int?i?=?0;?i?5;?i++)?{
          ????System.out.println(randomGenerator.nextInt(10));
          }

          擴(kuò)展閱讀:增強(qiáng)的偽隨機(jī)數(shù)生成器[15]

          JEP 382:使用新的 macOS 渲染庫

          macOS 為了提高圖形的渲染性能,在 2018 年 9 月拋棄了之前的 OpenGL 渲染庫 ,而使用了 Apple Metal 進(jìn)行代替。Java 17 這次更新開始支持 Apple Metal,不過對(duì)于 API 沒有任何改變,這一些都是內(nèi)部修改。

          擴(kuò)展閱讀:macOS Mojave 10.14 Release Notes[16]Apple Metal[17]

          JEP 391:支持 macOS/AArch64 架構(gòu)

          起因是 Apple 在 2020 年 6 月的 WWDC 演講中宣布,將開啟一項(xiàng)長(zhǎng)期的將 Macintosh 計(jì)算機(jī)系列從 x64 過度到 AArch64 的長(zhǎng)期計(jì)劃,因此需要盡快的讓 JDK 支持 macOS/AArch64 。

          Linux 上的 AArch64 支持以及在 Java 16 時(shí)已經(jīng)支持,可以查看之前的文章了解。

          擴(kuò)展:Java 16 新功能介紹 - JEP 386[18]

          JEP 398:刪除已棄用的 Applet API

          Applet 是使用 Java 編寫的可以嵌入到 HTML 中的小應(yīng)用程序,嵌入方式是通過普通的 HTML 標(biāo)記語法,由于早已過時(shí),幾乎沒有場(chǎng)景在使用了。

          示例:嵌入 Hello.class

          <applet?code="Hello.class"?height=200?width=200>applet>

          Applet API 在 Java 9 時(shí)已經(jīng)標(biāo)記了廢棄,現(xiàn)在 Java 17 中將徹底刪除。

          JEP 403:更強(qiáng)的 JDK 內(nèi)部封裝

          如 Java 16 的 JEP 396 中描述的一樣,為了提高 JDK 的安全性,使?--illegal-access?選項(xiàng)的默認(rèn)模式從允許更改為拒絕。通過此更改,JDK 的內(nèi)部包和 API(關(guān)鍵內(nèi)部 API[19]?除外)將不再默認(rèn)打開。

          但是在 Java 17 中,除了?sun.misc.Unsafe?,使用?--illegal-access?命令也不能打開 JDK 內(nèi)部的強(qiáng)封裝模式了,除了?sun.misc.Unsafe?API .

          在 Java 17 中使用?--illegal-access?選項(xiàng)將會(huì)得到一個(gè)命令已經(jīng)移除的警告。

          ???bin?./java?-version
          openjdk?version?"17"?2021-09-14
          OpenJDK?Runtime?Environment?(build?17+35-2724)
          OpenJDK?64-Bit?Server?VM?(build?17+35-2724,?mixed?mode,?sharing)
          ???bin?./java?--illegal-access=warn
          OpenJDK?64-Bit?Server?VM?warning:?Ignoring?option?--illegal-access=warn;?support?was?removed?in?17.0

          擴(kuò)展閱讀:JEP 403:更強(qiáng)的 JDK 內(nèi)部封裝[20]Java 16 新功能介紹[21]

          JEP 406:switch 的類型匹配(預(yù)覽)

          如?instanceof?一樣,為?switch?也增加了類型匹配自動(dòng)轉(zhuǎn)換功能。

          在之前,使用?instanceof?需要如下操作:

          if?(obj?instanceof?String)?{
          ????String?s?=?(String)?obj;????//?grr...
          ????...
          }

          多余的類型強(qiáng)制轉(zhuǎn)換,而現(xiàn)在:

          if?(obj?instanceof?String?s)?{
          ????//?Let?pattern?matching?do?the?work!
          ????...
          }

          switch?也可以使用類似的方式了。

          static?String?formatterPatternSwitch(Object?o)?{
          ????return?switch?(o)?{
          ????????case?Integer?i?->?String.format("int?%d",?i);
          ????????case?Long?l????->?String.format("long?%d",?l);
          ????????case?Double?d??->?String.format("double?%f",?d);
          ????????case?String?s??->?String.format("String?%s",?s);
          ????????default????????->?o.toString();
          ????};
          }

          對(duì)于?null?值的判斷也有了新的方式。

          //?Java?17?之前
          static?void?testFooBar(String?s)?{
          ????if?(s?==?null)?{
          ????????System.out.println("oops!");
          ????????return;
          ????}
          ????switch?(s)?{
          ????????case?"Foo",?"Bar"?->?System.out.println("Great");
          ????????default???????????->?System.out.println("Ok");
          ????}
          }
          //?Java?17
          static?void?testFooBar(String?s)?{
          ????switch?(s)?{
          ????????case?null?????????->?System.out.println("Oops");
          ????????case?"Foo",?"Bar"?->?System.out.println("Great");
          ????????default???????????->?System.out.println("Ok");
          ????}
          }

          擴(kuò)展閱讀:JEP 406:switch 的類型匹配(預(yù)覽)[22]

          JEP 407:移除 RMI Activation

          移除了在 JEP 385 中被標(biāo)記廢除的 RMI(Remote Method Invocation)Activation,但是 RMI 其他部分不會(huì)受影響。

          RMI Activation 在 Java 15 中的 JEP 385 已經(jīng)被標(biāo)記為過時(shí)廢棄,至今沒有收到不良反饋,因此決定在 Java 17 中正式移除。

          擴(kuò)展閱讀:JEP 407:移除 RMI Activation[23]

          JEP 409:密封類(Sealed Classes)

          Sealed Classes?在 Java 15 中的 JEP 360 中提出,在 Java 16 中的 JEP 397 再次預(yù)覽,現(xiàn)在 Java 17 中成為正式的功能,相比 Java 16 并沒有功能變化,這里不再重復(fù)介紹,想了解的可以參考之前文章。

          擴(kuò)展閱讀:Java 16 新功能介紹[24],JEP 409: Sealed Classes[25]

          JEP 401:移除實(shí)驗(yàn)性的 AOT 和 JIT 編譯器

          在 Java 9 的 JEP 295 中,引入了實(shí)驗(yàn)性的提前編譯 jaotc 工具,但是這個(gè)特性自從引入依賴用處都不太大,而且需要大量的維護(hù)工作,所以在 Java 17 中決定刪除這個(gè)特性。

          主要移除了三個(gè) JDK 模塊:

          1. jdk.aot - jaotc 工具。
          2. Jdk.internal.vm.compiler - Graal 編譯器。
          3. jdk.internal.vm.compiler.management

          同時(shí)也移除了部分與 AOT 編譯相關(guān)的 HotSpot 代碼:

          1. src/hotspot/share/aot?— dumps and loads AOT code
          2. Additional code guarded by?#if INCLUDE_AOT

          JEP 411:棄用 Security Manager

          Security Manager?在 JDK 1.0 時(shí)就已經(jīng)引入,但是它一直都不是保護(hù)服務(wù)端以及客戶端 Java 代碼的主要手段,為了 Java 的繼續(xù)發(fā)展,決定棄用 Security Manager,在不久的未來進(jìn)行刪除。

          @Deprecated(since="17",?forRemoval=true)
          public?class?SecurityManager?{
          ?//?...
          }

          JEP 412:外部函數(shù)和內(nèi)存 API (孵化)

          新的 API 允許 Java 開發(fā)者與 JVM 之外的代碼和數(shù)據(jù)進(jìn)行交互,通過調(diào)用外部函數(shù),可以在不使用 JNI 的情況下調(diào)用本地庫。

          這是一個(gè)孵化功能;需要添加--add-modules jdk.incubator.foreign來編譯和運(yùn)行 Java 代碼。

          歷史

          • Java 14?JEP 370[26]引入了外部?jī)?nèi)存訪問 API(孵化器)。
          • Java 15?JEP 383[27]引入了外部?jī)?nèi)存訪問 API(第二孵化器)。
          • Java 16?JEP 389[28]引入了外部鏈接器 API(孵化器)。
          • Java 16?JEP 393[29]引入了外部?jī)?nèi)存訪問 API(第三孵化器)。
          • Java 17?JEP 412[30]引入了外部函數(shù)和內(nèi)存 API(孵化器)。

          擴(kuò)展閱讀:JEP 412:外部函數(shù)和內(nèi)存 API (孵化)[31]

          JEP 414:Vector API(二次孵化)

          在 Java 16 中引入一個(gè)新的 API 來進(jìn)行向量計(jì)算,它可以在運(yùn)行時(shí)可靠的編譯為支持的 CPU 架構(gòu),從而實(shí)現(xiàn)更優(yōu)的計(jì)算能力。

          現(xiàn)在 Java 17 中改進(jìn)了 Vector API 性能,增強(qiáng)了例如對(duì)字符的操作、字節(jié)向量與布爾數(shù)組之間的相互轉(zhuǎn)換等功能。

          JEP 415:指定上下文的反序列化過濾器

          Java 中的序列化一直都是非常重要的功能,如果沒有序列化功能,Java 可能都不會(huì)占據(jù)開發(fā)語言的主導(dǎo)地位,序列化讓遠(yuǎn)程處理變得容易和透明,同時(shí)也促進(jìn)了 Java EE 的成功。

          但是 Java 序列化的問題也很多,它幾乎會(huì)犯下所有的可以想象的錯(cuò)誤,為開發(fā)者帶來持續(xù)的維護(hù)工作。但是要說明的是序列化的概念是沒有錯(cuò)的,把對(duì)象轉(zhuǎn)換為可以在 JVM 之間自由傳輸,并且可以在另一端重新構(gòu)建的能力是完全合理的想法,問題在于 Java 中的序列化設(shè)計(jì)存在風(fēng)險(xiǎn),以至于爆出過很多和序列化相關(guān)的漏洞。

          反序列化危險(xiǎn)的一個(gè)原因是,有時(shí)候我們不好驗(yàn)證將要進(jìn)行反序列化的內(nèi)容是否存在風(fēng)險(xiǎn),而傳入的數(shù)據(jù)流可以自由引用對(duì)象,很有可能這個(gè)數(shù)據(jù)流就是攻擊者精心構(gòu)造的惡意代碼。

          所以,JEP 415 允許在反序列化時(shí),通過一個(gè)過濾配置,來告知本次反序列化允許或者禁止操作的類,反序列化時(shí)碰到被禁止的類,則會(huì)反序列化失敗。

          反序列化示例

          假設(shè) Dog 類中的 Poc 是惡意構(gòu)造的類,但是正常反序列化是可以成功的。

          package?com.wdbyte.java17;

          import?java.io.ByteArrayInputStream;
          import?java.io.ByteArrayOutputStream;
          import?java.io.IOException;
          import?java.io.ObjectInputStream;
          import?java.io.ObjectOutputStream;
          import?java.io.Serializable;

          /**
          ?*?@author?niulang
          ?*/

          public?class?JEP415?{
          ????public?static?void?main(String[]?args)?throws?IOException,?ClassNotFoundException?{
          ????????Dog?dog?=?new?Dog("哈士奇");
          ????????dog.setPoc(new?Poc());
          ????????//?序列化?-?對(duì)象轉(zhuǎn)字節(jié)數(shù)組
          ????????ByteArrayOutputStream?byteArrayOutputStream?=?new?ByteArrayOutputStream();
          ????????try?(ObjectOutputStream?objectOutputStream?=?new?ObjectOutputStream(byteArrayOutputStream);)?{
          ????????????objectOutputStream.writeObject(dog);
          ????????}
          ????????byte[]?bytes?=?byteArrayOutputStream.toByteArray();
          ????????//?反序列化?-?字節(jié)數(shù)組轉(zhuǎn)對(duì)象
          ????????ByteArrayInputStream?byteArrayInputStream?=?new?ByteArrayInputStream(bytes);
          ????????ObjectInputStream?objectInputStream?=?new?ObjectInputStream(byteArrayInputStream);
          ????????Object?object?=?objectInputStream.readObject();
          ????????System.out.println(object.toString());
          ????}
          }

          class?Dog?implements?Serializable?{
          ????private?String?name;
          ????private?Poc?poc;

          ????public?Dog(String?name)?{
          ????????this.name?=?name;
          ????}

          ????@Override
          ????public?String?toString()?{
          ????????return?"Dog{"?+?"name='"?+?name?+?'\''?+?'}';
          ????}
          ??//?get...set...
          }

          class?Poc?implements?Serializable{

          }

          輸出結(jié)果:

          Dog{name='哈士奇'}

          反序列化過濾器

          在 Java 17 中可以自定義反序列化過濾器,攔截不允許的類。

          package?com.wdbyte.java17;

          import?java.io.ByteArrayInputStream;
          import?java.io.ByteArrayOutputStream;
          import?java.io.IOException;
          import?java.io.ObjectInputFilter;
          import?java.io.ObjectInputStream;
          import?java.io.ObjectOutputStream;
          import?java.io.Serializable;

          /**
          ?*?@author?niulang
          ?*/

          public?class?JEP415?{
          ????public?static?void?main(String[]?args)?throws?IOException,?ClassNotFoundException?{
          ????????Dog?dog?=?new?Dog("哈士奇");
          ????????dog.setPoc(new?Poc());
          ????????//?序列化?-?對(duì)象轉(zhuǎn)字節(jié)數(shù)組
          ????????ByteArrayOutputStream?byteArrayOutputStream?=?new?ByteArrayOutputStream();
          ????????try?(ObjectOutputStream?objectOutputStream?=?new?ObjectOutputStream(byteArrayOutputStream);)?{
          ????????????objectOutputStream.writeObject(dog);
          ????????}
          ????????byte[]?bytes?=?byteArrayOutputStream.toByteArray();
          ????????//?反序列化?-?字節(jié)數(shù)組轉(zhuǎn)對(duì)象
          ????????ByteArrayInputStream?byteArrayInputStream?=?new?ByteArrayInputStream(bytes);
          ????????ObjectInputStream?objectInputStream?=?new?ObjectInputStream(byteArrayInputStream);
          ????????//?允許?com.wdbyte.java17.Dog?類,允許?java.base?中的所有類,拒絕其他任何類
          ????????ObjectInputFilter?filter?=?ObjectInputFilter.Config.createFilter(
          ????????????????????????"com.wdbyte.java17.Dog;java.base/*;!*");
          ????????objectInputStream.setObjectInputFilter(filter);
          ????????Object?object?=?objectInputStream.readObject();
          ????????System.out.println(object.toString());
          ????}
          }

          class?Dog?implements?Serializable?{
          ????private?String?name;
          ????private?Poc?poc;

          ????public?Dog(String?name)?{
          ????????this.name?=?name;
          ????}

          ????@Override
          ????public?String?toString()?{
          ????????return?"Dog{"?+?"name='"?+?name?+?'\''?+?'}';
          ????}
          ??//?get...set...
          }

          class?Poc?implements?Serializable{
          }

          這時(shí)反序列化會(huì)得到異常。

          Exception?in?thread?"main"?java.io.InvalidClassException:?filter?status:?REJECTED
          ?at?java.base/java.io.ObjectInputStream.filterCheck(ObjectInputStream.java:1412)
          ?at?java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2053)
          ?at?java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1907)
          ?....

          擴(kuò)展閱讀:JEP 415:指定上下文的反序列化過濾器[32]

          Java 18

          Java 18?在 2022 年 3 月 22 日正式發(fā)布,這次更新共帶來 9 個(gè)新功能。

          Java 18 不是一個(gè)長(zhǎng)期支持版本,如果你想要升級(jí)自己的 JDK 版本的話,我會(huì)更推薦 Java17。目前來看,遷移到 Java17 的項(xiàng)目越來越多,尤其是在國外。

          OpenJDK Java 18 下載:https://jdk.java.net/18/

          OpenJDK Java 18 文檔:https://openjdk.java.net/projects/jdk/18/

          JEP描述
          JEP 400默認(rèn)為 UTF-8[33]
          JEP 408簡(jiǎn)單的網(wǎng)絡(luò)服務(wù)器[34]
          JEP 413Java API 文檔中的代碼片段[35]
          JEP 416使用方法句柄重新實(shí)現(xiàn)核心反射[36]
          JEP 417Vector API(三次孵化)[37]
          JEP 418互聯(lián)網(wǎng)地址解析 SPI[38]
          JEP 419Foreign Function & Memory API (二次孵化)[39]
          JEP 420switch 模式匹配(二次預(yù)覽)[40]
          JEP 421棄用完成刪除[41]

          JEP 400:默認(rèn) UTF-8 字符編碼

          JDK 一直都是支持 UTF-8 字符編碼,這次是把 UTF-8 設(shè)置為了默認(rèn)編碼,也就是在不加任何指定的情況下,默認(rèn)所有需要用到編碼的 JDK API 都使用 UTF-8 編碼,這樣就可以避免因?yàn)椴煌到y(tǒng),不同地區(qū),不同環(huán)境之間產(chǎn)生的編碼問題。

          Mac OS 默認(rèn)使用 UTF-8 作為默認(rèn)編碼,但是其他操作系統(tǒng)上,編碼可能取決于系統(tǒng)的配置或者所在區(qū)域的設(shè)置。如中國大陸的 windows 使用 GBK 作為默認(rèn)編碼。很多同學(xué)初學(xué) Java 時(shí)可能都遇到過一個(gè)正常編寫 Java 類,在 windows 系統(tǒng)的命令控制臺(tái)中運(yùn)行卻出現(xiàn)亂碼的情況。

          使用下面的命令可以輸出 JDK 的當(dāng)前編碼。

          #?Mac?系統(tǒng),默認(rèn)?UTF-8
          ???~?java?-XshowSettings:properties?-version?2>&1?|?grep?file.encoding
          ????file.encoding?=?UTF-8
          ????file.encoding.pkg?=?sun.io
          ???~

          下面編寫一個(gè)簡(jiǎn)單的 Java 程序,輸出默認(rèn)字符編碼,然后輸出中文漢字 ”你好“,看看 Java 18 和 Java 17 運(yùn)行區(qū)別。

          系統(tǒng)環(huán)境:Windows 11

          import?java.nio.charset.Charset;

          public?class?Hello{
          ????public?static?void?main(String[]?args)?{
          ????????System.out.println(Charset.defaultCharset());????????System.out.println("你好");????}
          }

          從下面的運(yùn)行結(jié)果中可以看到,使用 JDK 17 運(yùn)行輸出的默認(rèn)字符編碼是 GBK,輸出的中文 ”你好“ 已經(jīng)亂碼了;亂碼是因?yàn)?VsCode 默認(rèn)的文本編輯器編碼是 UTF-8,而中國地區(qū)的 Windows 11 默認(rèn)字符編碼是 GBK,也是 JDK 17 默認(rèn)獲取到的編碼,所以會(huì)在控制臺(tái)輸出時(shí)亂碼;而使用 JDK 18 輸出的默認(rèn)編碼就是 UTF-8,所以可以正常的輸出中文 ”你好“。

          img

          JEP 408:簡(jiǎn)單的 Web 服務(wù)器

          在 Java 18 中,提供了一個(gè)新命令?jwebserver,運(yùn)行這個(gè)命令可以啟動(dòng)一個(gè)簡(jiǎn)單的 、最小化的靜態(tài) Web 服務(wù)器,它不支持 CGI 和 Servlet,所以最好的使用場(chǎng)景是用來測(cè)試、教育、演示等需求。

          其實(shí)在如 Python、Ruby、PHP、Erlang 等許多平臺(tái)都提供了開箱即用的 Web 服務(wù)器,可見一個(gè)簡(jiǎn)單的 Web 服務(wù)器是一個(gè)常見的需求,Java 一直沒有這方面的支持,現(xiàn)在可以了。

          在 Java 18 中,使用?jwebserver?啟動(dòng)一個(gè) Web 服務(wù)器,默認(rèn)發(fā)布的是當(dāng)前目錄。

          在當(dāng)前目錄創(chuàng)建一個(gè)網(wǎng)頁文件 index.html

          <html>
          <head>
          <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>
          head>
          <body>
          <h1>標(biāo)題h1>
          body>
          html>

          啟動(dòng)?jwebserver.

          ???bin?./jwebserver
          Binding?to?loopback?by?default.?For?all?interfaces?use?"-b?0.0.0.0"?or?"-b?::".
          Serving?/Users/darcy/develop/jdk-18.jdk/Contents/Home/bin?and?subdirectories?on?127.0.0.1?port?8000
          URL?http://127.0.0.1:8000/

          瀏覽器訪問:

          img

          有請(qǐng)求時(shí)會(huì)在控制臺(tái)輸出請(qǐng)求信息:

          127.0.0.1?-?-?[26/3月/2022:16:53:30?+0800]?"GET?/favicon.ico?HTTP/1.1"?404?-
          127.0.0.1?-?-?[26/3月/2022:16:55:13?+0800]?"GET?/?HTTP/1.1"?200?-

          通過?help?參數(shù)可以查看?jwebserver?支持的參數(shù)。

          ???bin?./jwebserver?--help
          Usage:?jwebserver?[-b?bind?address]?[-p?port]?[-d?directory]
          ??????????????????[-o?none|info|verbose]?[-h?to?show?options]
          ??????????????????[-version?to?show?version?information]
          Options:
          -b,?--bind-address????-?綁定地址.?Default:?127.0.0.1?(loopback).
          ????????????????????????For?all?interfaces?use?"-b?0.0.0.0"?or?"-b?::".
          -d,?--directory???????-?指定目錄.?Default:?current?directory.
          -o,?--output??????????-?Output?format.?none|info|verbose.?Default:?info.
          -p,?--port????????????-?綁定端口.?Default:?8000.
          -h,?-?,?--help????????-?Prints?this?help?message?and?exits.
          -version,?--version???-?Prints?version?information?and?exits.
          To?stop?the?server,?press?Ctrl?+?C.

          JEP 413:Javadoc 中支持代碼片段

          在 Java 18 之前,已經(jīng)支持在 Javadoc 中引入代碼片段,這樣可以在某些場(chǎng)景下更好的展示描述信息,但是之前的支持功能有限,比如我想高亮代碼片段中的某一段代碼是無能為力的?,F(xiàn)在 Java 18 優(yōu)化了這個(gè)問題,增加了?@snippet?來引入更高級(jí)的代碼片段。

          在 Java 18 之前,使用?

          {@code ...}
          ?來引入代碼片段。

          ?/**
          ??*?時(shí)間工具類
          ??* Java 18 之前引入代碼片段:
          ??*?
          {@code
          ??*?????public?static?String?timeStamp()?{
          ??*????????long?time?=?System.currentTimeMillis();
          ??*?????????return?String.valueOf(time?/?1000);
          ??*?????}
          ??*?}

          ??*
          ??*/

          生成 Javadoc 之后,效果如下:

          img

          高亮代碼片段

          從 Java 18 開始,可以使用?@snippet?來生成注釋,且可以高亮某個(gè)代碼片段。

          /**
          ?*?在?Java?18?之后可以使用新的方式
          ?*?下面的代碼演示如何使用?{@code?Optional.isPresent}:
          ?*?{@snippet?:
          ?*?if?(v.isPresent())?{
          ?*?????System.out.println("v:?"?+?v.get());
          ?*?}
          ?*?}
          ?*
          ?*?高亮顯示?println
          ?*
          ?*?{@snippet?:
          ?*?class?HelloWorld?{
          ?*?????public?static?void?main(String...?args)?{
          ?*?????????System.out.println("Hello?World!");??????//?@highlight?substring="println"
          ?*?????}
          ?*?}
          ?*?}
          ?*
          ?*/

          效果如下,更直觀,效果更好。

          img

          正則高亮代碼片段

          甚至可以使用正則來高亮某一段中的某些關(guān)鍵詞:

          /**
          ??*?正則高亮:
          ??*?{@snippet?:
          ??*???public?static?void?main(String...?args)?{
          ??*???????for?(var?arg?:?args)?{?????????????????//?@highlight?region?regex?=?"\barg\b"
          ??*???????????if?(!arg.isBlank())?{
          ??*???????????????System.out.println(arg);
          ??*???????????}
          ??*???????}??????????????????????????????????????//?@end
          ??*???}
          ??*???}
          ??*/

          生成的 Javadoc 效果如下:

          img

          替換代碼片段

          可以使用正則表達(dá)式來替換某一段代碼。

          ?/**
          ???*?正則替換:
          ???*?{@snippet?:
          ???*?class?HelloWorld?{
          ???*?????public?static?void?main(String...?args)?{
          ???*?????????System.out.println("Hello?World!");??//?@replace?regex='".*"'?replacement="..."
          ???*?????}
          ???*?}
          ???*?}
          ???*/

          這段注釋會(huì)生成如下 Javadoc 效果。

          class?HelloWorld?{
          ????public?static?void?main(String...?args)?{
          ????????System.out.println(...);
          ????}
          }

          附:Javadoc 生成方式

          #?使用?javadoc?命令生成?Javadoc?文檔
          ???bin?./javadoc?-public?-sourcepath?./src?-subpackages?com?-encoding?utf-8?-charset?utf-8?-d?./javadocout
          #?使用?Java?18?的?jwebserver?把生成的?Javadoc?發(fā)布測(cè)試
          ???bin?./jwebserver?-d?/Users/darcy/develop/javadocout

          訪問測(cè)試:

          img

          JEP 416:使用方法句柄重新實(shí)現(xiàn)反射核心功能

          Java 18 改進(jìn)了?java.lang.reflect.MethodConstructor?的實(shí)現(xiàn)邏輯,使之性能更好,速度更快。這項(xiàng)改動(dòng)不會(huì)改動(dòng)相關(guān) API ,這意味著開發(fā)中不需要改動(dòng)反射相關(guān)代碼,就可以體驗(yàn)到性能更好反射。

          OpenJDK 官方給出了新老實(shí)現(xiàn)的反射性能基準(zhǔn)測(cè)試結(jié)果。

          Java 18 之前:

          Benchmark?????????????????????????????????????Mode??Cnt???Score??Error??Units
          ReflectionSpeedBenchmark.constructorConst?????avgt???10??68.049?±?0.872??ns/opReflectionSpeedBenchmark.constructorPoly??????avgt???10??94.132?±?1.805??ns/op
          ReflectionSpeedBenchmark.constructorVar???????avgt???10??64.543?±?0.799??ns/op
          ReflectionSpeedBenchmark.instanceFieldConst???avgt???10??35.361?±?0.492??ns/opReflectionSpeedBenchmark.instanceFieldPoly????avgt???10??67.089?±?3.288??ns/op
          ReflectionSpeedBenchmark.instanceFieldVar?????avgt???10??35.745?±?0.554??ns/op
          ReflectionSpeedBenchmark.instanceMethodConst??avgt???10??77.925?±?2.026??ns/op
          ReflectionSpeedBenchmark.instanceMethodPoly???avgt???10??96.094?±?2.269??ns/op
          ReflectionSpeedBenchmark.instanceMethodVar????avgt???10??80.002?±?4.267??ns/op
          ReflectionSpeedBenchmark.staticFieldConst?????avgt???10??33.442?±?2.659??ns/op
          ReflectionSpeedBenchmark.staticFieldPoly??????avgt???10??51.918?±?1.522??ns/op
          ReflectionSpeedBenchmark.staticFieldVar???????avgt???10??33.967?±?0.451??ns/op
          ReflectionSpeedBenchmark.staticMethodConst????avgt???10??75.380?±?1.660??ns/op
          ReflectionSpeedBenchmark.staticMethodPoly?????avgt???10??93.553?±?1.037??ns/op
          ReflectionSpeedBenchmark.staticMethodVar??????avgt???10??76.728?±?1.614??ns/op

          Java 18 的新實(shí)現(xiàn):

          Benchmark?????????????????????????????????????Mode??Cnt????Score???Error??Units
          ReflectionSpeedBenchmark.constructorConst?????avgt???10???32.392?±?0.473??ns/opReflectionSpeedBenchmark.constructorPoly??????avgt???10??113.947?±?1.205??ns/op
          ReflectionSpeedBenchmark.constructorVar???????avgt???10???76.885?±?1.128??ns/op
          ReflectionSpeedBenchmark.instanceFieldConst???avgt???10???18.569?±?0.161??ns/opReflectionSpeedBenchmark.instanceFieldPoly????avgt???10???98.671?±?2.015??ns/op
          ReflectionSpeedBenchmark.instanceFieldVar?????avgt???10???54.193?±?3.510??ns/op
          ReflectionSpeedBenchmark.instanceMethodConst??avgt???10???33.421?±?0.406??ns/op
          ReflectionSpeedBenchmark.instanceMethodPoly???avgt???10??109.129?±?1.959??ns/op
          ReflectionSpeedBenchmark.instanceMethodVar????avgt???10???90.420?±?2.187??ns/op
          ReflectionSpeedBenchmark.staticFieldConst?????avgt???10???19.080?±?0.179??ns/op
          ReflectionSpeedBenchmark.staticFieldPoly??????avgt???10???92.130?±?2.729??ns/op
          ReflectionSpeedBenchmark.staticFieldVar???????avgt???10???53.899?±?1.051??ns/op
          ReflectionSpeedBenchmark.staticMethodConst????avgt???10???35.907?±?0.456??ns/op
          ReflectionSpeedBenchmark.staticMethodPoly?????avgt???10??102.895?±?1.604??ns/op
          ReflectionSpeedBenchmark.staticMethodVar??????avgt???10???82.123?±?0.629??ns/op

          可以看到在某些場(chǎng)景下性能稍微好些。

          JEP 417:Vector API(三次孵化)

          在 Java 16 中引入一個(gè)新的 API 來進(jìn)行向量計(jì)算,它可以在運(yùn)行時(shí)可靠的編譯為支持的 CPU 架構(gòu),從而實(shí)現(xiàn)更優(yōu)的計(jì)算能力。

          在 Java 17 中改進(jìn)了 Vector API 性能,增強(qiáng)了例如對(duì)字符的操作、字節(jié)向量與布爾數(shù)組之間的相互轉(zhuǎn)換等功能。

          現(xiàn)在在 JDK 18 中將繼續(xù)優(yōu)化其性能。

          JEP 418:互聯(lián)網(wǎng)地址解析 SPI

          對(duì)于互聯(lián)網(wǎng)地址解析 SPI,為主機(jī)地址和域名地址解析定義一個(gè) SPI,以便java.net.InetAddress可以使用平臺(tái)內(nèi)置解析器以外的解析器。

          InetAddress?inetAddress?=?InetAddress.getByName("www.wdbyte.com");
          System.out.println(inetAddress.getHostAddress());
          //?輸出
          //?106.14.229.49

          JEP 419:Foreign Function & Memory API (第二次孵化)

          新的 API 允許 Java 開發(fā)者與 JVM 之外的代碼和數(shù)據(jù)進(jìn)行交互,通過調(diào)用外部函數(shù),可以在不使用 JNI 的情況下調(diào)用本地庫。

          這是一個(gè)孵化功能;需要添加--add-modules jdk.incubator.foreign來編譯和運(yùn)行 Java 代碼,Java 18 改進(jìn)了相關(guān) API ,使之更加簡(jiǎn)單易用。

          歷史

          • Java 14?JEP 370 (opens new window)[42]引入了外部?jī)?nèi)存訪問 API(孵化器)。
          • Java 15?JEP 383 (opens new window)[43]引入了外部?jī)?nèi)存訪問 API(第二孵化器)。
          • Java 16?JEP 389 (opens new window)[44]引入了外部鏈接器 API(孵化器)。
          • Java 16?JEP 393 (opens new window)[45]引入了外部?jī)?nèi)存訪問 API(第三孵化器)。
          • Java 17?JEP 412 (opens new window)[46]引入了外部函數(shù)和內(nèi)存 API(孵化器)。

          JEP 420:switch 表達(dá)式(二次孵化)

          從 Java 17 開始,對(duì)于 Switch 的改進(jìn)就已經(jīng)在進(jìn)行了,Java 17 的 JEP 406 已經(jīng)對(duì) Switch 表達(dá)式進(jìn)行了增強(qiáng),使之可以減少代碼量。

          下面是幾個(gè)例子:

          //?JDK?17?以前
          static?String?formatter(Object?o)?{
          ????String?formatted?=?"unknown";
          ????if?(o?instanceof?Integer?i)?{
          ????????formatted?=?String.format("int?%d",?i);
          ????}?else?if?(o?instanceof?Long?l)?{
          ????????formatted?=?String.format("long?%d",?l);
          ????}?else?if?(o?instanceof?Double?d)?{
          ????????formatted?=?String.format("double?%f",?d);
          ????}?else?if?(o?instanceof?String?s)?{
          ????????formatted?=?String.format("String?%s",?s);
          ????}
          ????return?formatted;
          }

          而在 Java 17 之后,可以通過下面的寫法進(jìn)行改進(jìn):

          //?JDK?17?之后
          static?String?formatterPatternSwitch(Object?o)?{
          ????return?switch?(o)?{
          ????????case?Integer?i?->?String.format("int?%d",?i);
          ????????case?Long?l????->?String.format("long?%d",?l);
          ????????case?Double?d??->?String.format("double?%f",?d);
          ????????case?String?s??->?String.format("String?%s",?s);
          ????????default????????->?o.toString();
          ????};
          }

          switch 可以和?null?進(jìn)行結(jié)合判斷:

          static?void?testFooBar(String?s)?{
          ????switch?(s)?{
          ????????case?null?????????->?System.out.println("Oops");????????case?"Foo",?"Bar"?->?System.out.println("Great");
          ????????default???????????->?System.out.println("Ok");
          ????}
          }

          case 時(shí)可以加入復(fù)雜表達(dá)式:

          static?void?testTriangle(Shape?s)?{
          ????switch?(s)?{
          ????????case?Triangle?t?&&?(t.calculateArea()?>?100)?->????????????System.out.println("Large?triangle");
          ????????default?->
          ????????????System.out.println("A?shape,?possibly?a?small?triangle");
          ????}
          }

          case 時(shí)可以進(jìn)行類型判斷:

          sealed?interface?S?permits?A,?B,?C?{}
          final?class?A?implements?S?{}
          final?class?B?implements?S?{}
          record?C(int?i)?implements?S?{}??//?Implicitly?final

          static?int?testSealedExhaustive(S?s)?{
          ????return?switch?(s)?{
          ????????case?A?a?->?1;
          ????????case?B?b?->?2;
          ????????case?C?c?->?3;
          ????};
          }

          擴(kuò)展:JEP 406:Switch 的類型匹配(預(yù)覽)[47]

          JEP 421:棄用刪除相關(guān)

          在未來將刪除 Finalization,目前 Finalization 仍默認(rèn)保持啟用狀態(tài),但是已經(jīng)可以手動(dòng)禁用;在未來的版本中,將會(huì)默認(rèn)禁用;在以后的版本中,它將被刪除。需要進(jìn)行資源管理可以嘗試?try-with-resources?或者?java.lang.ref.Cleaner。

          參考資料

          [1]

          恢復(fù)始終嚴(yán)格的浮點(diǎn)語義:?https://openjdk.java.net/jeps/306

          [2]

          增強(qiáng)的偽隨機(jī)數(shù)生成器:?https://openjdk.java.net/jeps/356

          [3]

          使用新的 macOS 渲染庫:?https://openjdk.java.net/jeps/382

          [4]

          支持 macOS/AArch64 架構(gòu):?https://openjdk.java.net/jeps/391

          [5]

          刪除已啟用的 Applet API:?https://openjdk.java.net/jeps/398

          [6]

          更強(qiáng)的封裝 JDK 內(nèi)部封裝:?https://openjdk.java.net/jeps/403

          [7]

          Switch 模式匹配(預(yù)覽):?https://openjdk.java.net/jeps/406

          [8]

          移除 RMI Activation:?https://openjdk.java.net/jeps/407

          [9]

          密封類(Sealed Classes):?https://openjdk.java.net/jeps/409

          [10]

          JEP 401:移除實(shí)驗(yàn)性的 AOT 和 JIT 編譯器:?https://openjdk.java.net/jeps/410

          [11]

          棄用 Security Manager:?https://openjdk.java.net/jeps/411

          [12]

          外部函數(shù)和內(nèi)存 API(孵化器):?https://openjdk.java.net/jeps/412

          [13]

          Vector API(第二孵化器):?https://openjdk.java.net/jeps/414

          [14]

          指定上下文的反序列化過濾器:?https://openjdk.java.net/jeps/415

          [15]

          增強(qiáng)的偽隨機(jī)數(shù)生成器:?https://openjdk.java.net/jeps/356

          [16]

          macOS Mojave 10.14 Release Notes:?https://developer.apple.com/documentation/macos-release-notes/macos-mojave-10_14-release-notes?preferredLanguage=occ#3035786

          [17]

          Apple Metal:?https://developer.apple.com/metal/

          [18]

          Java 16 新功能介紹 - JEP 386:?https://www.wdbyte.com/java/java-16/

          [19]

          關(guān)鍵內(nèi)部 API:?https://openjdk.java.net/jeps/260#Description

          [20]

          JEP 403:更強(qiáng)的 JDK 內(nèi)部封裝:?https://openjdk.java.net/jeps/403

          [21]

          Java 16 新功能介紹:?https://www.wdbyte.com/java/java-16/

          [22]

          JEP 406:switch 的類型匹配(預(yù)覽):?https://openjdk.java.net/jeps/406

          [23]

          JEP 407:移除 RMI Activation:?https://openjdk.java.net/jeps/407

          [24]

          Java 16 新功能介紹:?https://www.wdbyte.com/java/java-16/

          [25]

          JEP 409: Sealed Classes:?https://openjdk.java.net/jeps/409

          [26]

          JEP 370:?https://openjdk.java.net/jeps/370

          [27]

          JEP 383:?https://openjdk.java.net/jeps/383

          [28]

          JEP 389:?https://openjdk.java.net/jeps/389

          [29]

          JEP 393:?https://openjdk.java.net/jeps/393

          [30]

          JEP 412:?https://openjdk.java.net/jeps/412

          [31]

          JEP 412:外部函數(shù)和內(nèi)存 API (孵化):?https://openjdk.java.net/jeps/412

          [32]

          JEP 415:指定上下文的反序列化過濾器:?https://openjdk.java.net/jeps/415

          [33]

          默認(rèn)為 UTF-8:?https://openjdk.java.net/jeps/400

          [34]

          簡(jiǎn)單的網(wǎng)絡(luò)服務(wù)器:?https://openjdk.java.net/jeps/408

          [35]

          Java API 文檔中的代碼片段:?https://openjdk.java.net/jeps/413

          [36]

          使用方法句柄重新實(shí)現(xiàn)核心反射:?https://openjdk.java.net/jeps/416

          [37]

          Vector API(三次孵化):?https://openjdk.java.net/jeps/417

          [38]

          互聯(lián)網(wǎng)地址解析 SPI:?https://openjdk.java.net/jeps/418

          [39]

          Foreign Function & Memory API (二次孵化):?https://openjdk.java.net/jeps/419

          [40]

          switch 模式匹配(二次預(yù)覽):?https://openjdk.java.net/jeps/420

          [41]

          棄用完成刪除:?https://openjdk.java.net/jeps/421

          [42]

          JEP 370 (opens new window):?https://openjdk.java.net/jeps/370

          [43]

          JEP 383 (opens new window):?https://openjdk.java.net/jeps/383

          [44]

          JEP 389 (opens new window):?https://openjdk.java.net/jeps/389

          [45]

          JEP 393 (opens new window):?https://openjdk.java.net/jeps/393

          [46]

          JEP 412 (opens new window):?https://openjdk.java.net/jeps/412

          [47]

          JEP 406:Switch 的類型匹配(預(yù)覽):?https://www.wdbyte.com/java/java-17/#_7-jep-406-switch-的類型匹配-預(yù)覽


          我的新書《深入理解Java核心技術(shù)》已經(jīng)上市了,上市后一直蟬聯(lián)京東暢銷榜中,目前正在6折優(yōu)惠中,想要入手的朋友千萬不要錯(cuò)過哦~長(zhǎng)按二維碼即可購買~


          長(zhǎng)按掃碼享受6折優(yōu)惠





          往期推薦

          絕了!這個(gè)MySQL故障定位方法太好用了


          再有人問你什么是分庫分表,直接把這篇文章發(fā)給他


          JB出品,下一代IDE!!




          有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

          歡迎大家關(guān)注Java之道公眾號(hào)


          好文章,我在看??

          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  日韩亚洲欧美在线 | 在线欧美日韩 | 91九色在线观看视频 | 三级视频在线看 | 国产欧美高清在线观看 |