--- title: Java 14 & 15 æ°ç¹æ§æ¦è§ description: æ¦è§ JDK 14/15 çå ³é®ç¹æ§ï¼å¦ recordãææ¬åä¸ç©ºæéç²¾åæç¤ºçè¯è¨å¢å¼ºã category: Java tag: - Javaæ°ç¹æ§ head: - - meta - name: keywords content: Java 14,Java 15,record,ææ¬å,NullPointerException ç»è,模å¼å¹é ,JEP --- ## Java 14 JDK 14 äº 2020 å¹´ 3 æ 17 æ¥åå¸ï¼è¿æ¯ä¸ä¸ªé LTS çæ¬ã è¿ç¯æç« 伿éå ¶ä¸è¾ä¸ºéè¦çä¸äºæ°ç¹æ§è¿è¡è¯¦ç»ä»ç»ï¼ - [JEP 305: Pattern Matching for instanceofï¼instanceof 模å¼å¹é ï¼é¢è§ï¼](https://openjdk.org/jeps/305) - [JEP 358: Helpful NullPointerExceptions (空æéå¼å¸¸ç²¾åæç¤º)](https://openjdk.org/jeps/358) - [JEP 361: Switch Expressions (Standard) (switch 表达å¼, 转æ£)](https://openjdk.org/jeps/361) - [JEP 359: Records (Preview) (record å ³é®å, é¢è§ç¹æ§)](https://openjdk.org/jeps/359) - [JEP 368: Text Blocks (Second Preview) (ææ¬å, ç¬¬äºæ¬¡é¢è§)](https://openjdk.org/jeps/368) - [JEP 363: Remove the CMS Garbage Collector (ç§»é¤ CMS å徿¶éå¨)](https://openjdk.org/jeps/363) ä¸å¾æ¯ä» JDK 8 å° JDK 25 æ¯ä¸ªçæ¬çæ´æ°å¸¦æ¥çæ°ç¹æ§æ°éåæ´æ°æ¶é´ï¼  ### JEP 305: Pattern Matching for instanceofï¼instanceof 模å¼å¹é ï¼é¢è§ï¼ Java 14 ç»§ç»å° instanceof 模å¼å¹é ä½ä¸ºé¢è§ç¹æ§ï¼è¿æ¯ Java 14 å¼å ¥çåè½ï¼JEP 305ï¼ã è¯¥ç¹æ§å è®¸å¨ instanceof æ£æ¥çåæ¶è¿è¡ç±»å转æ¢ï¼é¿å äºæ¾å¼å¼ºå¶è½¬æ¢çéè¦ã注æï¼instanceof 模å¼å¹é å¨ Java 14 æ¯ç¬¬ä¸æ¬¡é¢è§ï¼JEP 305ï¼ï¼å¨ Java 15 æ¯ç¬¬äºæ¬¡é¢è§ï¼JEP 375ï¼ï¼æç»å¨ Java 16 转æ£ï¼JEP 394ï¼ã ### JEP 358: Helpful NullPointerExceptionsï¼ç©ºæéå¼å¸¸ç²¾åæç¤ºï¼ éè¿ JVM 忰䏿·»å `-XX:+ShowCodeDetailsInExceptionMessages`ï¼å¯ä»¥å¨ç©ºæéå¼å¸¸ä¸è·åæ´ä¸ºè¯¦ç»çè°ç¨ä¿¡æ¯ï¼æ´å¿«çå®ä½åè§£å³é®é¢ã ```java a.b.c.i = 99; // åè®¾è¿æ®µä»£ç ä¼åç空æé ``` Java 14 ä¹åï¼ ```java Exception in thread "main" java.lang.NullPointerException at NullPointerExample.main(NullPointerExample.java:5) ``` Java 14 ä¹åï¼ ```java // å¢å åæ°åæç¤ºçå¼å¸¸ä¸å¾æç¡®çåç¥äºåªéä¸ºç©ºå¯¼è´ Exception in thread "main" java.lang.NullPointerException: Cannot read field 'c' because 'a.b' is null. at Prog.main(Prog.java:5) ``` ### JEP 361: Switch Expressionsï¼switch 表达å¼ï¼æ åçï¼ Java 12 å¼å ¥ç switchï¼é¢è§ç¹æ§ï¼å¨ Java 14 å为æ£å¼çæ¬ï¼ä¸éè¦å¢å åæ°æ¥å¯ç¨ï¼ç´æ¥å¨ JDK 14 ä¸å°±è½ä½¿ç¨ã Java 12 为 switch 表达å¼å¼å ¥äºç±»ä¼¼ lambda è¯æ³æ¡ä»¶å¹é æååçæ§è¡åï¼ä¸éè¦å¤å breakï¼Java 13 æä¾äº `yield` æ¥å¨ block ä¸è¿åå¼ã ```java String result = switch (day) { case "M", "W", "F" -> "MWF"; case "T", "TH", "S" -> "TTS"; default -> { if(day.isEmpty()) yield "Please insert a valid day."; else yield "Looks like a Sunday."; } }; System.out.println(result); ``` ### JEP 359: Recordsï¼record ç±»ï¼é¢è§ï¼ `record` å ³é®åå¯ä»¥ç®å **æ°æ®ç±»**ï¼ä¸ä¸ª Java ç±»ä¸æ¦å®ä¾åå°±ä¸è½åä¿®æ¹ï¼çå®ä¹æ¹å¼ï¼ä½¿ç¨ `record` ä»£æ¿ `class` å®ä¹çç±»ï¼åªéè¦å£°æå±æ§ï¼å°±å¯ä»¥å¨è·å¾å±æ§çè®¿é®æ¹æ³ï¼ä»¥å `toString()`ï¼`hashCode()`, `equals()`æ¹æ³ã 类似äºä½¿ç¨ `class` å®ä¹ç±»ï¼åæ¶ä½¿ç¨äº lombok æä»¶ï¼å¹¶æä¸äº`@Getter,@ToString,@EqualsAndHashCode`注解ã ```java /** * è¿ä¸ªç±»å ·æä¸¤ä¸ªç¹å¾ * 1. æææå屿§é½æ¯final * 2. å ¨é¨æ¹æ³ç±æé æ¹æ³ï¼å两个æå屿§è®¿é®å¨ç»æï¼å ±ä¸ä¸ªï¼ * é£ä¹è¿ç§ç±»å°±å¾éå使ç¨recordæ¥å£°æ */ final class Rectangle implements Shape { final double length; final double width; public Rectangle(double length, double width) { this.length = length; this.width = width; } double length() { return length; } double width() { return width; } } /** * 1. ä½¿ç¨ record 声æçç±»ä¼èªå¨æ¥æä¸é¢ç±»ä¸çä¸ä¸ªæ¹æ³ * 2. å¨è¿åºç¡ä¸è¿éèµ äº equals()ï¼hashCode() æ¹æ³ä»¥å toString() æ¹æ³ * 3. toString æ¹æ³ä¸å æ¬æææå屿§çå符串表示形å¼åå ¶åç§° */ record Rectangle(float length, float width) { } ``` ### JEP 368: Text Blocksï¼ææ¬åï¼ç¬¬äºæ¬¡é¢è§ï¼ Java14 ä¸ï¼ææ¬åä¾ç¶æ¯é¢è§ç¹æ§ï¼ä¸è¿ï¼å ¶å¼å ¥äºä¸¤ä¸ªæ°ç转ä¹åç¬¦ï¼ - `\` : 表示è¡å°¾ï¼ä¸å¼å ¥æ¢è¡ç¬¦ - `\s`ï¼è¡¨ç¤ºåä¸ªç©ºæ ¼ ```java String str = "å¡å¿æåï¼ç´ å±¥æå¾ï¼çå¦éæ ï¼ä¸è以èªã"; String str2 = """ å¡å¿æåï¼ç´ å±¥æå¾ï¼ \ çå¦éæ ï¼ä¸è以èªã"""; System.out.println(str2);// å¡å¿æåï¼ç´ å±¥æå¾ï¼ çå¦éæ ï¼ä¸è以èªã String text = """ java c++\sphp """; System.out.println(text); //è¾åºï¼ java c++ php ``` ### å ¶ä»ç¹æ§ - ä» Java11 å¼å ¥ç ZGC ä½ä¸ºç»§ G1 è¿åçä¸ä¸ä»£ GC ç®æ³ï¼ä»æ¯æ Linux å¹³å°å° Java14 å¼å§æ¯æ MacOS å Windowsï¼ä¸ªäººæè§æ¯ç»äºå¯ä»¥å¨æ¥å¸¸å¼åå·¥å ·ä¸å ä½éªä¸ ZGC çææäºï¼è½ç¶å ¶å® G1 ä¹å¤ç¨ï¼ - [JEP 363: Remove the CMS Garbage Collector](https://openjdk.org/jeps/363) (ç§»é¤ CMS å徿¶éå¨ï¼åæèé) - æ°å¢äº jpackage å·¥å ·ï¼æ é å°åºç¨ææ jar å å¤ï¼è¿æ¯æä¸åå¹³å°çç¹æ§å ï¼æ¯å¦ linux ä¸ç`deb`å`rpm`ï¼window å¹³å°ä¸ç`msi`å`exe` ## Java 15 JDK 15 äº 2020 å¹´ 9 æ 15 æ¥åå¸ï¼è¿æ¯ä¸ä¸ªé LTS çæ¬ã è¿ç¯æç« 伿éå ¶ä¸è¾ä¸ºéè¦çä¸äºæ°ç¹æ§è¿è¡è¯¦ç»ä»ç»ï¼ - [JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector (Shenandoah GC, 转æ£)](https://openjdk.org/jeps/379) - [JEP 371: Hidden Classes (éèç±»)](https://openjdk.org/jeps/371) - [JEP 378: Text Blocks (Standard) (ææ¬å, 转æ£)](https://openjdk.org/jeps/378) - [JEP 360: Sealed Classes (Preview) (å¯å°ç±», é¢è§ç¹æ§)](https://openjdk.org/jeps/360) - [JEP 339: EdDSA (æ°åç¾åç®æ³)](https://openjdk.org/jeps/339) ä¸å¾æ¯ä» JDK 8 å° JDK 24 æ¯ä¸ªçæ¬çæ´æ°å¸¦æ¥æ°ç¹æ§æ°éåæ´æ°æ¶é´ï¼  ### JEP 379: Shenandoahï¼Shenandoah GCï¼æ åçï¼ Shenandoah å徿¶éå¨ä» Java 12 å¼å§ä½ä¸ºå®éªæ§ç¹æ§å¼å ¥ï¼ç»è¿å¤ä¸ªçæ¬çè¿ä»£åå®åï¼å¨ Java 15 ç»äºè½¬æ£ä¸ºæ£å¼ç¹æ§ã Shenandoah æ¯ Red Hat 主导å¼åçä½å»¶è¿å徿¶éå¨ï¼ä¸»è¦ç®æ æ¯ï¼ - 99.9% ç GC åé¡¿æ¶é´å°äº 10ms - åé¡¿æ¶é´ä¸å 大尿 å ³ - æ¯æä»å ç¾ MB å°å TB çå å å ä¸ G1 å ZGC ä¸åï¼Shenandoah éç¨å¹¶åæ è®°-æ´çç®æ³ï¼å¯ä»¥å¨ä¸åæ¢åºç¨çº¿ç¨çæ åµä¸è¿è¡åå¾åæ¶ã å¯ç¨ Shenandoah GCï¼ ```bash java -XX:+UseShenandoahGC className ``` ### JEP 339: EdDSAï¼æ°åç¾åç®æ³ï¼ æ°å å ¥äºä¸ä¸ªå®å ¨æ§åæ§è½é½æ´å¼ºçåºäº Edwards-Curve Digital Signature Algorithm ï¼EdDSAï¼å®ç°çæ°åç¾åç®æ³ã è½ç¶å ¶æ§è½ä¼äºç°æç ECDSA å®ç°ï¼ä¸è¿ï¼å®å¹¶ä¸ä¼å®å ¨å代 JDK ä¸ç°æçæ¤åæ²çº¿æ°åç¾åç®æ³( ECDSA)ã ```java KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519"); KeyPair kp = kpg.generateKeyPair(); byte[] msg = "test_string".getBytes(StandardCharsets.UTF_8); Signature sig = Signature.getInstance("Ed25519"); sig.initSign(kp.getPrivate()); sig.update(msg); byte[] s = sig.sign(); String encodedString = Base64.getEncoder().encodeToString(s); System.out.println(encodedString); ``` è¾åºï¼ ```plain 0Hc0lxxASZNvS52WsvnncJOH/mlFhnA8Tc6D/k5DtAX5BSsNVjtPF4R4+yMWXVjrvB2mxVXmChIbki6goFBgAg== ``` ### JEP 378: Text Blocksï¼ææ¬åï¼æ åçï¼ å¨ Java 15ï¼ææ¬åç»äºè½¬æ£ä¸ºæ£å¼åè½ç¹æ§ï¼ä¸åéè¦ `--enable-preview` åæ°å³å¯ä½¿ç¨ã ææ¬åæä¾äºä¸ç§æ´ç®æ´çæ¹å¼æ¥å®ä¹å¤è¡å符串ï¼ç¹å«éåç¨äº SQLãJSONãHTML çåºæ¯ã ### JEP 371: Hidden Classesï¼éèç±»ï¼ éèç±»æ¯ä¸ºæ¡æ¶ï¼frameworksï¼æè®¾è®¡çï¼æ¯æå¨æçæçç±»ï¼è¿äºç±»ä¸è½ç´æ¥è¢«å ¶ä»ç±»çåèç 使ç¨ï¼åªè½å¨è¿è¡æ¶éè¿åå°é´æ¥ä½¿ç¨å®ä»¬ã 主è¦ç¹ç¹ï¼ - ä¸å¯è¢«åç°ï¼éèç±»ä¸è½è¢«å ¶ä»ç±»ç´æ¥ä¾èµ - çå½å¨æçï¼é常å¨ä½¿ç¨å®æ¯åå°±ä¼è¢«å¸è½½ - æ§è½ä¼åï¼ä¸ºå¨æè¯è¨è¿è¡æ¶æä¾äºæ´å¥½çæ§è½æ¯æ éç¨åºæ¯ï¼ - 卿è¯è¨è¿è¡æ¶ï¼å¦ JavaScriptãGroovyï¼ - åèç çææ¡æ¶ï¼å¦ ASMãCGLIBï¼ - åå°ä»£çï¼å¦å¨æä»£çï¼ ### JEP 360: Sealed Classesï¼å¯å°ç±»ï¼é¢è§ï¼ **å¯å°ç±»ï¼Sealed Classesï¼** æ¯ Java 15 ä¸çä¸ä¸ªé¢è§æ°ç¹æ§ã 没æå¯å°ç±»ä¹åï¼å¨ Java ä¸å¦ææ³è®©ä¸ä¸ªç±»ä¸è½è¢«ç»§æ¿åä¿®æ¹ï¼æä»¬å¯ä»¥ä½¿ç¨`final` å ³é®å对类è¿è¡ä¿®é¥°ãä¸è¿ï¼è¿ç§æ¹å¼ä¸å¤ªçµæ´»ï¼ç´æ¥æä¸ä¸ªç±»çç»§æ¿åä¿®æ¹æ¸ éç»å µæ»äºã å¯å°ç±»å¯ä»¥å¯¹ç»§æ¿æè å®ç°å®ä»¬çç±»è¿è¡éå¶ï¼è¿æ ·è¿ä¸ªç±»å°±åªè½è¢«æå®ç类继æ¿ã ```java // æ½è±¡ç±» Person åªå 许 Employee å Manager ç»§æ¿ã public abstract sealed class Person permits Employee, Manager { //... } ``` å¦å¤ï¼ä»»ä½æ©å±å¯å°ç±»çç±»æ¬èº«é½å¿ 须声æä¸º `sealed`ã`non-sealed` æ `final`ã ```java public final class Employee extends Person { } public non-sealed class Manager extends Person { } ```  妿å 许æ©å±çåç±»åå°éç±»å¨åä¸ä¸ªæºä»£ç æä»¶éï¼å°éç±»å¯ä»¥ä¸ä½¿ç¨ permits è¯å¥ï¼Java ç¼è¯å¨å°æ£ç´¢æºæä»¶ï¼å¨ç¼è¯æä¸ºå°é类添å ä¸è®¸å¯çåç±»ã ### JEP 375: Pattern Matching for instanceofï¼instanceof 模å¼å¹é ï¼ç¬¬äºæ¬¡é¢è§ï¼ Java 15 ç»§ç»å° instanceof 模å¼å¹é ä½ä¸ºé¢è§ç¹æ§ï¼æ²¡æè¿è¡éå¤§è°æ´ï¼ä¸»è¦æ¯ä¸ºäºæ¶éæ´å¤ä½¿ç¨åé¦ã instanceof 模å¼å¹é å 许å¨ç±»åæ£æ¥çåæ¶è¿è¡åéç»å®ï¼é¿å äºæ¾å¼ç±»å转æ¢ï¼ä½¿ä»£ç æ´ç®æ´å®å ¨ã 示ä¾ï¼ ```java // ä¼ ç»åæ³ if (obj instanceof String) { String str = (String) obj; System.out.println(str.length()); } // 模å¼å¹é åæ³ if (obj instanceof String str) { System.out.println(str.length()); } ``` ### API å¢å¼º #### CharSequence å¢å¼º å¨ Java 15 ä¹åï¼å¦æä½ æ³å¤æä¸ä¸ª `StringBuilder`ã`StringBuffer` æè `CharBuffer` æ¯å¦ä¸ºç©ºï¼é常éè¦è°ç¨ `length() == 0`ã `CharSequence` æ¥å£æ·»å äºä¸ä¸ªé»è®¤æ¹æ³ `isEmpty()` æ¥å¤æå符åºå为空ï¼å¦ææ¯åè¿å trueã ```java public interface CharSequence { default boolean isEmpty() { return this.length() == 0; } } ``` ç±äº `String`ã`StringBuilder` çé½å®ç°äºè¿ä¸ªæ¥å£ï¼ç°å¨ä½ å¯ä»¥ç¨æ´ç»ä¸ãæ´å ·è¯ä¹åçæ¹å¼æ¥ç¼å夿é»è¾ãè¿å¯¹äºç¼åæ³å代ç ï¼å¤çåç§å符åºåï¼é常å好ã **注æï¼** `String` ç±»è½ç¶æ©å·²æäº `isEmpty()` æ¹æ³ï¼ä½é£ä¸ªæ¯ `String` èªå·±å®ä¹çï¼Java 15 è¿ä¸æ¥æ¯å°è¯¥è½åâ䏿µ®âå°äºæ¥å£å±ã #### TreeMap æ§è½æå è¿æ¯ä¸ä¸ªéå¸¸ç¡¬æ ¸çä¼åãè½ç¶ `putIfAbsent()`ã`compute()` çæ¹æ³æ©å¨ Java 8 å°±åºç°å¨ `Map` æ¥å£ä¸äºï¼ä½å¨ Java 15 ä¹åï¼`TreeMap` 并没æèªå·±å»å®ç°å®ä»¬ï¼èæ¯ç´æ¥æ²¿ç¨æ¥å£éç `default` å®ç°ã **Java 15 çåå**ï¼`TreeMap` ä¸é¨éåäºä»¥ä¸æ¹æ³ï¼ - `putIfAbsent()` - `computeIfAbsent()` - `computeIfPresent()` - `compute()` - `merge()` **为ä»ä¹è¦éåï¼** - **æ§è½æå**ï¼æ¥å£éçé»è®¤å®ç°é常æ¯è¾â笨âï¼å¾å¾éè¦è¿è¡å¤æ¬¡æ¥æ¾ï¼ä¾å¦å æ¥æ¾æ¯å¦åå¨ï¼åå³å®æ¯å¦æå ¥ï¼ã - **O(log n) ä¿è¯**ï¼`TreeMap` ä¼ååçå®ç°å¯ä»¥å°æ¥æ¾åæå ¥åå¹¶å¨ä¸æ¬¡çº¢é»æ éåä¸å®æï¼é¿å äºéå¤çæ æç´¢ï¼æ¾èæåäºå¨å¤çå¤§è§æ¨¡æ°æ®æ¶çæ§è¡æçã ### å ¶ä»ç¹æ§ - **Nashorn JavaScript 弿彻åºç§»é¤**ï¼Nashorn ä» Java8 å¼å§å¼å ¥ç JavaScript 弿ï¼Java9 对 Nashorn åäºäºå¢å¼ºï¼å®ç°äºä¸äº ES6 çæ°ç¹æ§ãå¨ Java 11 ä¸å°±å·²ç»è¢«å¼ç¨ï¼å°äº Java 15 就彻åºè¢«å é¤äºã - **DatagramSocket API éæ** - **ç¦ç¨ååºå¼ååéï¼Biased Lockingï¼**ï¼ååéçå¼å ¥å¢å äº JVM ç夿æ§å¤§äºå ¶å¸¦æ¥çæ§è½æåãä¸è¿ï¼ä½ ä»ç¶å¯ä»¥ä½¿ç¨ `-XX:+UseBiasedLocking` å¯ç¨ååéå®ï¼ä½å®ä¼æç¤ºè¿æ¯ä¸ä¸ªå·²å¼ç¨ç APIã - â¦â¦