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签名算法
了解即可