JDK14來(lái)了:9大重磅特性解讀,不容錯(cuò)過(guò)ME蟆!

JEP 305: Pattern Matching for instanceof (Preview)
JEP 358: Helpful NullPointerExceptions
JEP 361: Switch Expressions (Standard)
JEP 345: NUMA-Aware Memory Allocation for G1
JEP 349: JFR Event Streaming
JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination
JEP 363: Remove the CMS Garbage Collector
JEP 364: ZGC on macOS
JEP 368: Text Blocks (Second Preview)

JEP 305: Pattern Matching for instanceof (Preview)

很明顯這個(gè)特性跟使用instanceof有關(guān)区拳。平常我們寫(xiě)代碼是這樣的拘领。很明顯這不是最優(yōu)的方式,怎么看怎么別捏樱调, 代碼顯得有點(diǎn)冗余乏味约素,我們既要類型判斷,還要類型強(qiáng)轉(zhuǎn):

if (obj instanceof String) {
    String s = (String) obj;
    // use s
}

那么新的方式是怎么樣的呢笆凌?請(qǐng)往下看圣猎。厲不厲害,牛不牛逼:

if (obj instanceof String s) {
    //todo can use s here
} else {
    //todo can't use s here
}

而且還能用的更復(fù)雜一些乞而,需要注意的是送悔,下面這種寫(xiě)法時(shí),必須是&&爪模,而不能是||欠啤,為什么有這個(gè)限制,我想很容易理解吧:

if (obj instanceof String s && s.contains("afei")) {
    ... ...
}

JEP 358: Helpful NullPointerExceptions

這個(gè)特性優(yōu)點(diǎn)意思屋灌,絕對(duì)非常有空洁段。想象我們有一行這樣的代碼,并且在這里拋出了空指針共郭,那么祠丝,我們沒(méi)辦法知道空指針是由于a引起的,還是a.b引起的落塑,還是a.b.c引起的:

int index = a.b.c.i ;

所以纽疟,我們可能要將代碼改造成這樣罐韩,這樣才能在代碼拋出NPE時(shí)更容易定位問(wèn)題:

if (a!=null){
    if (a.b!=null){
        if (a.b.c!=null){
            int index = a.b.c.i ;
        }
    }
}

JEP358這個(gè)特性就是幫我們解決這個(gè)問(wèn)題的憾赁。假設(shè)我們的代碼還是這樣寫(xiě)的:int index = a.b.c.i ,并且由于a.b為null引起的空指針散吵,那么拋出的異常信息是這樣的龙考,這個(gè)異常就非常友好了吧:

Exception in thread "main" java.lang.NullPointerException: 
        Cannot read field "c" because "a.b" is null
    at Prog.main(Prog.java:5)

數(shù)組方式也是一樣的蟆肆,假設(shè)有一行這樣的代碼:int height = a[i][j][k],并且由于a[i][j]為空導(dǎo)致的NPE晦款,那么異常信息是這樣的:

Exception in thread "main" java.lang.NullPointerException:
        Cannot load from object array because "a[i][j]" is null
    at Prog.main(Prog.java:5)

JEP 361: Switch Expressions (Standard)

這個(gè)特性也是繼承自JDK13的JEP 354: Switch Expressions (Preview)炎功,有一段switch老語(yǔ)法代碼如下:

switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        System.out.println(6);
        break;
    case TUESDAY:
        System.out.println(7);
        break;
    case THURSDAY:
    case SATURDAY:
        System.out.println(8);
        break;
    case WEDNESDAY:
        System.out.println(9);
        break;
}

這段代碼顯得有點(diǎn)冗余,新的語(yǔ)法代碼如下缓溅,很明顯簡(jiǎn)練很多:

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

而且蛇损,新的switch語(yǔ)法能直接將其作為表達(dá)式,用法如下:

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
};

新的switch語(yǔ)法相比以前靈活了很多很多坛怪!

JEP 345: NUMA-Aware Memory Allocation for G1

了解這個(gè)特性之前淤齐,我們需要了解什么是NUMA。NUMA就是非統(tǒng)一內(nèi)存訪問(wèn)架構(gòu)(英語(yǔ):non-uniform memory access袜匿,簡(jiǎn)稱NUMA)更啄,是一種為多處理器的電腦設(shè)計(jì)的內(nèi)存架構(gòu),內(nèi)存訪問(wèn)時(shí)間取決于內(nèi)存相對(duì)于處理器的位置居灯。在NUMA下祭务,處理器訪問(wèn)它自己的本地內(nèi)存的速度比非本地內(nèi)存(內(nèi)存位于另一個(gè)處理器,或者是處理器之間共享的內(nèi)存)快一些怪嫌。如下圖所示义锥,Node0中的CPU如果訪問(wèn)Node0中的內(nèi)存,那就是訪問(wèn)本地內(nèi)存岩灭,如果它訪問(wèn)了Node1中的內(nèi)存缨该,那就是遠(yuǎn)程訪問(wèn),性能較差:

NUMA架構(gòu)

非統(tǒng)一內(nèi)存訪問(wèn)架構(gòu)的特點(diǎn)是:被共享的內(nèi)存物理上是分布式的川背,所有這些內(nèi)存的集合就是全局地址空間贰拿。所以處理器訪問(wèn)這些內(nèi)存的時(shí)間是不一樣的,顯然訪問(wèn)本地內(nèi)存的速度要比訪問(wèn)全局共享內(nèi)存或遠(yuǎn)程訪問(wèn)外地內(nèi)存要快些熄云。另外膨更,NUMA中內(nèi)存可能是分層的:本地內(nèi)存,群內(nèi)共享內(nèi)存缴允,全局共享內(nèi)存荚守。

JEP345希望通過(guò)實(shí)現(xiàn)NUMA-aware的內(nèi)存分配,改進(jìn)G1在大型機(jī)上的性能练般!現(xiàn)代的multi-socket服務(wù)器越來(lái)越多都有NUMA矗漾,意思是,內(nèi)存到每個(gè)socket的距離是不相等的薄料,內(nèi)存到不同的socket之間的訪問(wèn)是有性能差異的敞贡,這個(gè)距離越長(zhǎng),延遲就會(huì)越大摄职,性能就會(huì)越差L芤邸(https://openjdk.java.net/jeps/345)获列。只需要設(shè)置JVM參數(shù):+XX:+UseNUMA 后, 當(dāng)JVM初始化的時(shí)候(即Java應(yīng)用啟動(dòng)的時(shí)候),G1的Region集合就會(huì)被均勻的分散到所有有效的NUMA節(jié)點(diǎn)上蛔垢。

JEP 349: JFR Event Streaming

Java為了更方便的了解運(yùn)行的JVM情況击孩,在之前的版本中提供了JFR特性,即JDK Flight Recorder鹏漆。但是使用不太靈活巩梢。雖然JVM通過(guò)JFR暴露了超過(guò)500項(xiàng)數(shù)據(jù),但是其中大部分?jǐn)?shù)據(jù)只能通過(guò)解析JFR日志文件才能獲取得到艺玲,而不是實(shí)時(shí)獲取且改。用戶想要使用JFR的數(shù)據(jù)的話,用戶必須先開(kāi)啟JFR進(jìn)行記錄板驳,然后停止記錄又跛,再將飛行記錄的數(shù)據(jù)Dump到磁盤(pán)上,然后解析這個(gè)記錄文件若治。

// 下面這條命令會(huì)立即啟動(dòng)JFR并開(kāi)始使用templayte.jfc的配置收集60s的JVM信息慨蓝,并輸出到output.jfr中。
// 一旦記錄完成之后端幼,就可以復(fù)制jfr文件到你的工作環(huán)境使用jmc GUI來(lái)分析礼烈。
// 它幾乎包含了排查JVM問(wèn)題需要的所有信息,包括堆dump時(shí)的異常信息等婆跑。
jcmd <PID> JFR.start name=test duration=60s settings=template.jfc filename=output.jfr

這樣對(duì)于應(yīng)用程序分析很有效此熬,但是對(duì)于實(shí)時(shí)監(jiān)控卻并不友好,因?yàn)闊o(wú)法將JFR采集的信息實(shí)時(shí)動(dòng)態(tài)展示到儀表板上滑进。JEP349特性能夠通過(guò)異步訂閱的方式直接獲取JFR記錄的數(shù)據(jù)犀忱,而不需要分析Dump文件。如下這段代碼所示:

try (var rs = new RecordingStream()) {
  rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
  rs.enable("jdk.JavaMonitorEnter").withThreshold(Duration.ofMillis(10));
  rs.onEvent("jdk.CPULoad", event -> {
    System.out.println(event.getFloat("machineTotal"));
  });
  rs.onEvent("jdk.JavaMonitorEnter", event -> {
    System.out.println(event.getClass("monitorClass"));
  });
  rs.start();
}

JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination

ParallelScavenge + SerialOld GC的GC組合要被標(biāo)記為Deprecate了扶关,也就意味著阴汇,在接下來(lái)的某個(gè)JDK版本中,會(huì)徹底不兼容這種GC組合节槐。

JDK官方給出將這個(gè)GC組合標(biāo)記為Deprecate的理由是:這個(gè)GC組合需要大量的代碼維護(hù)工作搀庶,并且,這個(gè)GC組合很少被使用铜异。因?yàn)樗氖褂脠?chǎng)景應(yīng)該是一個(gè)很大的Young區(qū)配合一個(gè)很小的Old區(qū)哥倔,這樣的話,Old區(qū)用SerialOldGC去收集時(shí)停頓時(shí)間我們才能勉強(qiáng)接受揍庄。事實(shí)上咆蒿,這種場(chǎng)景很少使用,而且風(fēng)險(xiǎn)即可±啵總而言之,老年代能用UseParallelOldGC 缆镣,還需要什么SerialOldGC芽突,是吧!

JEP 363: Remove the CMS Garbage Collector

該來(lái)的總會(huì)來(lái)董瞻,自從G1橫空出世后寞蚌,CMS在JDK9中就被標(biāo)記為Deprecate了(JEP 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector),那么CMS被徹底移除也就是一個(gè)時(shí)間問(wèn)題了钠糊。

基于Region分代是大勢(shì)所趨挟秤,CMS的設(shè)計(jì)還是落后了一點(diǎn),而且它的碎片化問(wèn)題抄伍,給你的JVM實(shí)例就像埋了一顆炸彈。說(shuō)不定哪次就在你的業(yè)務(wù)高峰期來(lái)一次FGC,這可是采用Mark—Sweep-Compact算法的SerialOldGC回收晌砾,JVM中性能最差的垃圾回收方式吞瞪,停頓個(gè)幾秒鐘,上十秒都有可能岗喉。

當(dāng)然秋度,如果你JDK14中你還是配置的CMS(-XX:+UseConcMarkSweepGC),JVM不會(huì)報(bào)錯(cuò)钱床,只是給出一個(gè)告警信息荚斯,JVM會(huì)自動(dòng)回退以默認(rèn)GC方式啟動(dòng)JVM:

Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; \
support was removed in <version>
and the VM will continue execution using the default collector.

EP 364: ZGC on macOS

很簡(jiǎn)單,就是在macOS上支持ZGC查牌,沒(méi)什么太多需要說(shuō)明的事期。

JEP 368: Text Blocks (Second Preview)

這個(gè)特性對(duì)應(yīng)JDK13的JEP 355: Text Blocks (Preview),只不過(guò)這是Second Preview而已纸颜,所以刑赶,筆者只簡(jiǎn)單解決一下這個(gè)新的語(yǔ)法。

如果有一段SQL懂衩,老的語(yǔ)法是這樣寫(xiě)的:

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = 'INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";

新的語(yǔ)法是這樣寫(xiě)的:

String query = """
               SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
               WHERE `CITY` = 'INDIANAPOLIS'
               ORDER BY `EMP_ID`, `LAST_NAME`;
               """;

如果有一段腳本需要執(zhí)行撞叨,老的語(yǔ)法是這樣的:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("function hello() {\n" +
                         "    print('\"Hello, world\"');\n" +
                         "}\n" +
                         "\n" +
                         "hello();\n");

而新的語(yǔ)法是這樣的:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("""
                         function hello() {
                             print('"Hello, world"');
                         }
                         
                         hello();
                         """);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市浊洞,隨后出現(xiàn)的幾起案子牵敷,更是在濱河造成了極大的恐慌,老刑警劉巖法希,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枷餐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡苫亦,警方通過(guò)查閱死者的電腦和手機(jī)毛肋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門怨咪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人润匙,你說(shuō)我怎么就攤上這事诗眨。” “怎么了孕讳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵匠楚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我厂财,道長(zhǎng)芋簿,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任璃饱,我火速辦了婚禮与斤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荚恶。我一直安慰自己幽告,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布裆甩。 她就那樣靜靜地躺著冗锁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嗤栓。 梳的紋絲不亂的頭發(fā)上冻河,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音茉帅,去河邊找鬼叨叙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛堪澎,可吹牛的內(nèi)容都是我干的擂错。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼樱蛤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钮呀!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起昨凡,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤爽醋,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后便脊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蚂四,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了遂赠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片久妆。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖跷睦,靈堂內(nèi)的尸體忽然破棺而出筷弦,到底是詐尸還是另有隱情,我是刑警寧澤送讲,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布奸笤,位于F島的核電站惋啃,受9級(jí)特大地震影響哼鬓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜边灭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一异希、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绒瘦,春花似錦称簿、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至该酗,卻和暖如春授药,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呜魄。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工悔叽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爵嗅。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓娇澎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親睹晒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子趟庄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354