JDK17 新特性跟學梳理
- JDK17 背景介紹
- 一、JDK 17對Switch語句的增強
- 二、字符串拼接
- 三、強制轉換
- 四、密封類Sealed Classes
- 五、Record類
- 六、優化空指針異常信息
- 七、ZGC垃圾收集器
- 八、JVM常量API
- 九、重寫Socket底層API
- 十、JDK飛行記錄事件流
- 十一、EdDSA簽名算法
- 十二、隱藏類
- 十三、對Value-Based類型的警告
- 十四、統一的PRNG接口(Enhanced Pseudo-Random Number Generators)
- 十五、特定于上下文的反序列化過濾器
- 十五、恢復始終嚴格的浮點語義
JDK17 背景介紹
- 關注版本:LTS(Long-Term Support 長期支持
- 目前主流版本
- 主要應用
- Spring FrameWork 6.X 要求最低JDK17版本
- SpringBoot 3.0要求最低JDK17版本
- Kafka 3.00表示不再支持JDK8
- Jenkins在最新的2.357版本發表聲明最低支持JDK11
一、JDK 17對Switch語句的增強
JDK 17支持多case同返回值的便捷書寫,以及yield關鍵字返回變量返回值
代碼示例:
public class Main {public static void main(String[] args) {// JDK 8switchOld();// JDK 12switchNew();// JDK 17switchNewer();}/*** 功能描述: JDK 8 的Switch語句** @param* @return void* @date 2025/7/28 22:52* @author Derrick**/public static void switchOld() {String name = "徐庶";String alias = "";switch (name) {case "周瑜":alias = "公瑾";break;case "徐庶":alias = "元直";break;case "項羽":alias = "西楚霸王";break;case "張三":case "李四":alias = "王五";break;case "小米su7":case "小米yu7":alias = "小米智能車";System.out.println("小米智能車");break;}System.out.println("JDK8 alias:" + alias);}/*** 功能描述: JDK 12 的Switch語句** @param* @return void* @date 2025/7/28 22:52* @author Derrick**/public static void switchNew() {String name = "徐庶";String alias = switch (name) {case "周瑜" -> "公瑾";case "徐庶" -> "元直";case "項羽" -> "西楚霸王";default -> throw new IllegalStateException("Unexpected value: " + name);};System.out.println("JDK17 alias:" + alias);}/*** 功能描述: JDK 17 的Switch語句** @param* @return void* @date 2025/7/28 22:57* @author Derrick**/public static void switchNewer() {String name = "小米su7";String alias = switch (name) {case "周瑜" -> "公瑾";case "徐庶" -> "元直";case "項羽" -> "西楚霸王";// JDK 17版本新特性case "張三", "李四" -> "王五";case "小米su7", "小米yu7" -> {System.out.println("小米智能車");// yield關鍵字作為變量的返回值yield "小米智能車";}default -> throw new IllegalStateException("Unexpected value: " + name);};System.out.println("JDK17 alias:" + alias);}
}
二、字符串拼接
JDK 17中
\是置于末尾,作用是將2行轉為1行
\s是單個空白字符
package com.itheima.methods;/*** @ClassName: StringWay* @Description:* @Author: Derrick* @Date: 2025/7/28*/public class StringWay {private String oldStr = "<html>\n" +"<body>\n" +"<h1>Hello, World!</h1>\n" +"<body>\n" +"</html>\n";private String newStr = """<html><body><h1>Hello, World!</h1></body></html>""";// JDK 17中\是置于末尾,作用:將2行轉為1行 \s是單個空白字符private String newerStr = """<html>\<b\sody><h1>Hello, World!</h1></body></html>""";public StringWay() {System.out.println("JDK 8" + dealWithStringOld(oldStr));System.out.println("JDK 15" + dealWithStringOld(newStr));System.out.println("JDK 17" + dealWithStringOld(newerStr));}public String dealWithStringOld(String oldStr) {return oldStr;}
}
控制臺打印效果
JDK 8<html>
<body>
<h1>Hello, World!</h1>
<body>
</html>JDK 15<html><body><h1>Hello, World!</h1></body>
</html>JDK 17<html> <b ody><h1>Hello, World!</h1></body>
</html>
三、強制轉換
JDK 17可以便捷書寫包裝類的強制類型轉換
package com.itheima.methods;/*** @ClassName: ChangeInstance* @Description:* @Author: Derrick* @Date: 2025/7/28*/public class ChangeInstance {public ChangeInstance() {oldInstance(1);newInstance("對");}/*** 功能描述: JDK 8中需要強制轉換對應類型** @param* @param o* @return void* @date 2025/7/28 23:27* @author Derrick**/public void oldInstance(Object o) {if (o instanceof Integer) {Integer i = (Integer) o;System.out.println(i.intValue());} else if (o instanceof String) {String s = (String) o;System.out.println(s.charAt(0));}}/*** 功能描述: JDK 14中優化** @param* @param o* @return void* @date 2025/7/28 23:28* @author Derrick**/public void newInstance(Object o) {if (o instanceof Integer i) {System.out.println(i.intValue());} else if (o instanceof String s) {System.out.println(s.charAt(0));}}
}
打印效果如下:
1
對
四、密封類Sealed Classes
permits關鍵字,限制只有子類才能繼承父類。
子類必須使用non-sealed或者final關鍵字,final表示不能再被子子類繼承,non-sealed表示能被子子類繼承。
密封類和子類必須同處于一個包下,如果不在一個包下,就會報錯。
子類必須直接繼承自密封類,不能間接繼承,否則會報錯。
密封類的好處:(1)密封類更加安全,可以限制子子類的繼承 (2).密封類更加可控,減少代碼復雜性,易于維護
密封類代碼示例:
package com.itheima.methods;/*** @ClassName: SealedTest* @Description: permits關鍵字,限制只有SealedSon才能繼承SealedFather類* @Author: Derrick* @Date: 2025/7/29*/public abstract sealed class SealedFather permits SealedSon {}
子類代碼示例
package com.itheima.methods;/*** @ClassName: SealedSon* @Description: 子類必須使用non-sealed或者final關鍵字* @Author: Derrick* @Date: 2025/7/29*/public non-sealed class SealedSon extends SealedFather {
}
五、Record類
類似lombok的屬性只讀對象
IDEA創建class的時候選擇Record
Record示例如下:
package com.itheima.methods;/*** @RecordName: UserRecord* @Description:* @Author: Derrick* @Date: 2025/7/29*/
public record UserRecord(Long id, String userName) {
}
編譯的.class字節碼文件如下:
package com.itheima.methods;public record UserRecord(Long id, String userName) {public UserRecord(Long id, String userName) {this.id = id;this.userName = userName;}public Long id() {return this.id;}public String userName() {return this.userName;}
}
Main函數
import com.itheima.methods.ChangeInstance;
import com.itheima.methods.StringWay;
import com.itheima.methods.UserRecord;public class Main {public static void main(String[] args) {// RecordUserRecord userRecordOne = new UserRecord(1L, "Lily");UserRecord userRecordTwo = new UserRecord(1L, "Lily");System.out.println("userRecordOne.name:" + userRecordOne.userName());System.out.println("userRecordOne:" + userRecordOne);System.out.println("userRecordTwo.name:" + userRecordTwo.userName());System.out.println("userRecordTwo:" + userRecordTwo);System.out.println(userRecordOne.equals(userRecordTwo));}
}
控制臺打印
userRecordOne.name:Lily
userRecordOne:UserRecord[id=1, userName=Lily]
userRecordTwo.name:Lily
userRecordTwo:UserRecord[id=1, userName=Lily]
true
這里可以看到Record對象的屬性值相同,就是一個對象
六、優化空指針異常信息
這個改動是JDK 14的,這里特別講解一下
可以便捷查看空指針異常出自哪一句代碼的哪個對象為null
代碼示例
public static void main(String[] args) {// 解決空指針String str = null;int length = str.length();System.out.println("字符串長度:" + length);}
控制臺打印
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is nullat Main.main(Main.java:34)
可以看到JDK14針對哪個對象空指針是有說明的
七、ZGC垃圾收集器
JDK11誕生,JDK15正式使用,JDK17已經很成熟
優點:垃圾回收不卡頓(stop the world少于10ms),Java開發不用愁
可以看到JDK17的垃圾回收期性能最優
使用方式,配置如下即可,因為JDK11和JDK17默認的垃圾回收期是G1
-XX:+UseZGC
八、JVM常量API
比如String的源碼,獲取字符串常量的描述describeConstable,設置字符串常量的描述resolveConstantDesc
/*** Returns an {@link Optional} containing the nominal descriptor for this* instance, which is the instance itself.** @return an {@link Optional} describing the {@linkplain String} instance* @since 12*/@Overridepublic Optional<String> describeConstable() {return Optional.of(this);}/*** Resolves this instance as a {@link ConstantDesc}, the result of which is* the instance itself.** @param lookup ignored* @return the {@linkplain String} instance* @since 12*/@Overridepublic String resolveConstantDesc(MethodHandles.Lookup lookup) {return this;}
九、重寫Socket底層API
源碼如下
public abstract class SocketImpl implements SocketOptions {private static final boolean USE_PLAINSOCKETIMPL = usePlainSocketImpl();private static boolean usePlainSocketImpl() {PrivilegedAction<String> pa = () -> NetProperties.get("jdk.net.usePlainSocketImpl");@SuppressWarnings("removal")String s = AccessController.doPrivileged(pa);return (s != null) && !s.equalsIgnoreCase("false");}/*** Creates an instance of platform's SocketImpl*/@SuppressWarnings("unchecked")static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) {if (USE_PLAINSOCKETIMPL) {return (S) new PlainSocketImpl(server);} else {return (S) new NioSocketImpl(server);}}
}
十、JDK飛行記錄事件流
比如Spring Boot中Spring Boot Actuator模塊可以啟動記錄JFR記錄,可以通過在應用程序的配置文件中設置一下屬性來啟用JFR記錄
十一、EdDSA簽名算法
了解即可