java9及其以上版本
- 一、JDK17 LTS 常用新特性
- 1、switch语句的增强
- 2、字符串拼接
- 3、判断类型instanceof自动类型转换
- 4、密封类 关键字 sealed permits
- 5、record类
- 6、优化空指针异常
- 7、ZGC垃圾收集器
一、JDK17 LTS 常用新特性
1、switch语句的增强
在 Java 17中,switch 表达式得到了显著增强,支持了模式匹配(pattern matching)和 yield 语句。不过,需要注意的是,这里的 yield 不是关键字,而是 switch 表达式中用于返回值的表达式。
在 Java 17 之前,switch 语句主要用于整型和枚举类型,并且通常用于选择执行哪个代码块。而在 Java 17 中,switch 表达式(注意是表达式,不是语句)可以返回一个值,并且支持更广泛的类型(如字符串、对象等)以及模式匹配。
使用新的 switch 表达式时,你可以使用 -> 符号和表达式(或代码块)来指定每个 case 的结果。然而,在某些情况下,你可能想要从 switch 表达式的某个 case 中返回一个值,并立即退出 switch。在这种情况下,你可以使用类似于局部变量声明的语法,但使用 yield 关键字来返回该值。
以下是一个示例,展示了如何在 Java 17 中使用 switch 表达式和 yield:
String text = "Hello";
String result = switch (text) {
case "Hello" -> {
System.out.println("Matched Hello");
yield "Greeting"; // 使用 yield 返回一个值
}
case "World" -> "Salutation";
default -> {
System.out.println("No match found");
yield "Unknown"; // 使用 yield 返回一个默认值
}
};
System.out.println(result); // 输出:Greeting
在上面的示例中,switch 表达式根据 text 变量的值进行匹配,并使用 yield 语句从每个 case 中返回一个字符串。注意,每个 case 都可以是一个代码块,并且在这个代码块中,你可以使用 yield 来返回一个值,该值将成为整个 switch 表达式的结果。
需要注意的是,虽然这种语法看起来像是在使用局部变量,但实际上 yield 并不是声明一个变量;它只是从 switch 表达式中返回一个值。此外,yield 只能用在 switch 表达式的 case 分支中,并且每个 case 分支必须有一个 yield 语句(除非它是空的,或者是 throw 语句)。
其他使用案例如下图:
2、字符串拼接
3、判断类型instanceof自动类型转换
可以看到上图中jdk8的instanceof判断类型后,还需要手动做一次强制类型转换,jdk17可以简化写法。
4、密封类 关键字 sealed permits
限制继承,被sealed修饰的父类只能被后面permits修饰的指定子类继承。并且指定子类必须用non-sealed(可以被孙子类继承)或者final(此子类无法再被孙子类继承)修饰。
- 注意:
1、密封类的父类和子类必须在同一个包下。
2、被permits修饰的子类只能继承sealed修饰的父类,不能继承其他类。
public sealed interface Shape permits Circle, Rectangle {
}
public final class Circle implements Shape {
}
public non-sealed class Rectangle implements Shape {
}
// 尝试创建一个不在permits列表中的类来实现Shape会导致编译错误
// public final class Triangle implements Shape { ... } // 编译错误
5、record类
类似lombok的属性只读对象,此类可以隐式的实现全参构造方法(没有无参构造方法)和属性的get方法,没有set方法。也会重写equals(), hashCode(), toString()。
record类的特点:
紧凑的语法:Record类允许你使用更简洁的语法来定义数据类。
自动生成方法:Record类自动为你生成equals(), hashCode(), toString(), 以及所有的getter方法。
不可变性:Record类的字段默认是final的,这意味着Record类的实例是不可变的。
组件解构:Record类支持组件解构(component decomposition),允许你在模式匹配中使用它们。
record类的定义和普通class是不一样的,代码如下:
public record Point(int x, int y) {
// 这里不需要显式定义任何方法,因为Record类会自动为你生成
}
6、优化空指针异常
可以具体定位到哪一行的哪一个方法报空指针,以前只能定位到哪一行
7、ZGC垃圾收集器
垃圾回收不卡顿,JVM ZGC(Z Garbage Collector)解释
ZGC是Oracle在JDK
11中引入的一种创新垃圾收集算法,其设计目标主要是为了实现低延迟和高吞吐量的内存管理。以下是关于ZGC的详细解释:
一、主要特点
低延迟:ZGC的主要目标是确保持续较短的暂停时间,通过减少STW(Stop-The-World)暂停来实现。JDK 11中,ZGC的停顿时间不超过10ms,且不会随着堆内存的增大而变长。在JDK 16及之后的版本中,GC暂停时间已经缩小到1ms以内,并且时间复杂度是O(1),即GC停顿时间是一个固定值,不会受堆内存大小影响。
高吞吐量:ZGC通过优化垃圾收集操作和内存分配策略,可以在高负载的情况下提供更高的吞吐量。这意味着ZGC可以在短时间内完成更多的垃圾收集任务,从而提高Java应用程序的性能。
高内存利用率:ZGC通过动态调整内存布局和回收策略,可以更有效地利用内存资源。这使得ZGC可以在有限的内存空间内运行更多的Java应用程序实例,从而降低内存成本。
二、工作原理ZGC采用了全新的设计思路,摒弃了传统的分代收集策略,而是将整个堆内存看作一个整体。它使用读屏障(Read
Barrier)和染色指针(Colored Pointer)技术来实现并发标记和整理。ZGC的工作过程可以分为以下几个阶段:并发标记(Concurrent Marking):ZGC在标记阶段采用SATB(Snapshot-At-The-Beginning)算法,通过读屏障记录对象引用关系的变化。同时,ZGC引入了染色指针技术,将对象的引用信息存储在指针本身,从而避免了额外的内存开销。
再标记(Remark):在并发标记完成后,ZGC会暂停应用线程进行短暂的再标记操作,以处理在并发标记阶段未能处理的对象引用变化。这个停顿时间通常非常短,对应用性能的影响微乎其微。
并发整理(Concurrent Relocation):在再标记完成后,ZGC会进入并发整理阶段。与传统垃圾收集器的整理阶段不同,ZGC的整理操作是并发的,即与应用线程同时运行。这得益于ZGC的染色指针技术,使得对象在移动过程中仍然可以被正确地访问。
引用更新(Reference Processing)和弱引用处理(Weak Reference
Processing):在并发整理过程中,ZGC还需要处理对象的引用更新和弱引用。
三、性能优势
线程无关性:ZGC是一个线程无关的垃圾收集器,这意味着它可以在不同的线程之间并行执行垃圾收集任务,进一步提高应用程序的吞吐量。
无锁设计:ZGC采用了无锁设计,避免了锁定导致的竞争条件和死锁等问题,进一步提高了应用程序的性能。 四、适用场景ZGC非常适合对延迟敏感的应用场景,如在线交易、实时数据分析等。同时,由于其可伸缩性设计,ZGC也适用于大规模堆内存和高吞吐量应用,是云计算和大数据领域的理想选择