JDK17的新特性写法

一、介绍

JDK 17 是 Java Development Kit(Java 开发工具包)的一个版本,是 Oracle 公司提供的 Java SE(Java 平台,标准版)的一部分。以下是 JDK 17 的一些基本信息:

  1. 版本号:JDK 17 的完整版本号是 17,它是 Java SE 17 的版本。

  2. 发布日期:JDK 17 v17.0.0 在 2021 年 9 月 14 日正式发布。

  3. LTS 版本:JDK 17 被标记为 “LTS”(长期支持)版本。LTS 版本提供长期支持和维护,适合用于生产环境。

  4. 特性更新:JDK 17 引入了一些新的特性、改进和增强,包括但不限于密封类、基础类型的模式匹配、日期时间API的升级等。

  5. 垃圾回收器:JDK 17 包含了多种垃圾回收器,包括 ZGC、G1GC、ParallelGC 等,以满足不同场景下的需求。

二、新特性

1)switch

可以不用再写break了,可以进行简化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.banmoon.switches;

import cn.hutool.core.util.StrUtil;

public class OldSwitchMain {

public static void main(String[] args) {
String name = "半月无霜";
int age;
switch (name) {
case "半月无霜":
age = 18;
break;
case "cc":
age = 66;
break;
case "溪月":
System.out.println("溪月20岁");
age = 20;
break;
case "九月":
case "八月":
age = 22;
break;
default:
age = 0;
break;
}
System.out.println(StrUtil.format("姓名:{},年龄:{}", name, age));
}

}

新写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.banmoon.switches;

import cn.hutool.core.util.StrUtil;

public class NewSwitchMain {

public static void main(String[] args) {
String name = "半月无霜";
int age = switch (name) {
case "半月无霜" -> 18;
case "cc" -> 66;
case "溪月" -> {
System.out.println("溪月20岁");
yield 20;
}
case "九月", "八月" -> 22;
default -> 0;
};
System.out.println(StrUtil.format("姓名:{},年龄:{}", name, age));
}
}

可以对比一下它们之间的代码差距

image-20231118193539546


除了上面这种增强外,switch关键字还支持了对类的类型进行判断,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.banmoon.switches;

import cn.hutool.core.date.DateUtil;

import java.util.Date;

public class ClassSwitchMain {

public static void main(String[] args) {
Object o1 = "123";
Object o2 = new Date();
System.out.println(switchMethod(o1));
System.out.println(switchMethod(o2));
}

private static String switchMethod(Object o) {
return switch (o) {
case String str -> "字符串类型:" + str;
case Number number -> "数字类型:" + number;
case Date date -> "日期类型:" + DateUtil.formatDateTime(date);
default -> "其他类型";
};
}
}

2)字符串三引号

如果在代码中编写sql,或者有换行的长文本的时候,往往充斥着各种\n,十分影响阅读,如同下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.banmoon.stringQuotationMark;

public class OldMain {

public static void main(String[] args) {
String sql = "select\n" +
" id,\n" +
" username,\n" +
" password\n" +
"from sys_user\n" +
"where \n" +
" username = '%s'";
System.out.printf(sql, "半月无霜");
}
}

但现在可以通过"""...""",三个引号就可以得到解决,看着十分的清爽。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.banmoon.stringQuotationMark;

public class NewMain {

public static void main(String[] args) {
String sql = """
select
id,
username,
password
from sys_user
where
username = '%s'
""";
System.out.printf(sql, "半月无霜");
}

}

话说,这"""的设计是不是借鉴了python呢?越来越好了

3)instanceof增强

在以前我们使用instanceof关键字后,还需要带一个强转,例如下面的这段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.banmoon.instanceofEnhance;

public class OldInstanceofMain {

public static void main(String[] args) {
Object o1 = "1";
Object o2 = 1;
instanceOf(o1);
instanceOf(o2);
}

private static void instanceOf(Object o) {
if (o instanceof Integer) {
Integer i = (Integer) o;
System.out.println("数字:" + i);
} else if (o instanceof String) {
String str = (String) o;
System.out.println("字符串:" + str);
} else {
System.out.println("其他类型");
}
}

}

而新写法也比较简单,可以这样写,如果匹配直接就转换了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.banmoon.instanceofEnhance;

public class NewInstanceofMain {

public static void main(String[] args) {
Object o1 = "1";
Object o2 = 1;
instanceOf(o1);
instanceOf(o2);
}

private static void instanceOf(Object o) {
if (o instanceof Integer i) {
System.out.println("数字:" + i);
} else if (o instanceof String str) {
System.out.println("字符串:" + str);
} else {
System.out.println("其他类型");
}
}

}

4)密封类(Sealec Classes)

提供了一个新的关键字sealec,它的作用修饰父类、接口,变成一个密封类

同时还提供了一个permits,指定与父类接口同包的类才能继承或者实现

如下演示

首先,我们有一个父类

1
2
3
4
package com.banmoon.sealecClasses;

public sealed class Person permits Teacher, Student {
}

这个父类有两个直接子类StudentTeacher

1
2
3
4
package com.banmoon.sealecClasses;

public final class Student extends Person {
}
1
2
3
4
package com.banmoon.sealecClasses;

public sealed class Teacher extends Person permits EnglishTeacher, ChineseTeacher {
}

可以看到,这两个子类都是直接继承Person的,且在同一个包下面

同时,Teacher又规定了它的两个子类是EnglishTeacherChineseTeacher

1
2
3
4
package com.banmoon.sealecClasses;

public non-sealed class EnglishTeacher extends Teacher {
}
1
2
3
4
package com.banmoon.sealecClasses;

public non-sealed class ChineseTeacher extends Teacher{
}

大家伙应该都已经发现了下面这几个特性

  • 如果父类使用了sealed关键字,那么它就必须要用permits关键字指定子类

  • 子类要么使用finalno-sealed关键字,要么自己再次使用sealed关键字成为一个父类,并指定子类

  • 他们都在同一个包下面,且不允许其它类进行继承

我们来试一下,我们在另一个包创建Engineer,并继承Person

1
2
3
4
5
6
package com.banmoon.sealecClasses.other;

import com.banmoon.sealecClasses.Person;

public final class Engineer extends Person {
}

请看下面的图片

image-20231118214533425

5)Record类

Record类,里面的属性是只读的,只提供了获取方法,且提供一个全参的构造函数。

如下有一个UserRecord

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.banmoon.recordClasses;

public record UserRecord(Integer id, String username, String password) {

public static void main(String[] args) {
UserRecord user1 = new UserRecord(1, "半月无霜", "abc123");
System.out.printf("帐号ID:%d,用户名:%s,密码:%s%n", user1.id, user1.username, user1.password);
UserRecord user2 = new UserRecord(1, "半月无霜", "abc123");
System.out.printf("帐号ID:%d,用户名:%s,密码:%s%n", user1.id, user1.username, user1.password);
System.out.println(user1.equals(user2));
}

}

Record类已经帮我们重写了equals()hashCode()toString()方法

6)NullPointException优化

在以前的JDK版本中,我们有这样的问题,一行代码要是连续get获取对象中的对象。

如果万一没有做好校验,那么就会爆空指针异常,但仅仅只会报出在哪一行。如下面这段代码

1
2
3
4
5
6
7
8
9
10
11
12
package com.banmoon.NullPoint;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {

private User user;

}
1
2
3
4
5
6
7
8
9
10
package com.banmoon.NullPoint;

public class NullPointMain {

public static void main(String[] args) {
User user = new User(new User(new User(null)));
System.out.println(user.getUser().getUser().getUser().getUser());
}

}

报错NullPointException是这样子的,只告诉了在第几行

image-20231118220458340

那么在JDK17中,这个报错信息会是怎么样的呢

image-20231118220649097

好的,它已经将是哪个方法是null的已经标出来了,这样定位空指针就简单了。

7、ZGC垃圾收集器

ZGC是一种针对大堆和低延迟的垃圾回收器,它的目标是减少垃圾回收期间的停顿时间,并提供可预测和稳定的性能。

目前来说JDK21中,实现了ZGC的分代收集。

这款收集器,先让行业内大佬先行使用,我们持续观望中

三、最后

好了,讲讲为什么突然看起了JDK17呢?

还得是因为SpringBoot3使用了这个版本,要进行学习还是得先简单过一下JDK17中的内容。

我是半月,你我一同共勉!!!