0%

JDK8之后的JDK 17 新特性

这里介绍相比于JDK8,JDK 17中支持、提供的新特性

abstract.png

Record 记录类

JDK17中新增一种特殊的类——Record 记录类,用于表示不可变的数据。Record类会自动生成、提供 全参构造器(按属性声明顺序的构造器)、与成员变量同名的访问器方法(getter方法)、equals()、hashCode()、toString()方法。该类适用于dto传输数据的场景,在功能上非常类似于Python的具名元组。记录类的不可变性的体现在:

  • 所有成员变量都是final。成员变量一旦通过构造器完成初始化后就不能被修改。故对于记录类而言,不存在成员变量的修改器方法(setter方法)
  • Record类是隐式的final类。故不能有抽象方法、不可被继承并派生子类

Record类支持的行为:

  • Compact Constructor紧凑构造器:用来定义调用全参构造器时的前置行为。语法上类似构造器,但没有参数列表。常用于参数校验、初始化初始化成员变量
  • 重载版本的构造器:由于Record类会自动生成一个全参的构造器。故我们也可以定义其他重载版本的构造器
  • 静态方法:可定义静态方法。常用作工具方法、工厂方法
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public record PersonInfo(
String name,

Integer age,

String remark
) {
/**
* Compact Constructor 紧凑构造器
*/
public PersonInfo {
// 参数校验
if(age<0) {
throw new RuntimeException("年龄不能为负值");
} else if( name==null ) {
throw new RuntimeException("姓名不能为空");
}

// 成员变量初始化
if( remark==null ) {
remark = "This is default remak";
}
}

/**
* 重载版本的标准构造器
* @param name
*/
public PersonInfo(String name) {
this(name, 18, null);
}

/***** 可定义静态方法. 常用作工具方法、工厂方法 *************/
public static PersonInfo of(String name) {
return new PersonInfo(name);
}

public static String getNameUpperCase(PersonInfo personInfo) {
if( personInfo.name()!=null ) {
return personInfo.name().toUpperCase();
}
return null;
}
/*****************************************************/

/**
* 测试
*/
public static void main(String[] args) {
PersonInfo p1 = new PersonInfo("Aaron", 33, "hello");
System.out.println("p1.name(): " + p1.name());
System.out.println("p1.age(): " + p1.age());
System.out.println("p1.remark(): " + p1.remark());
System.out.println("PersonInfo.getNameUpperCase(p1): " + PersonInfo.getNameUpperCase(p1));

PersonInfo p2 = new PersonInfo("Bob", 71, null);
System.out.println("p2.toString: " + p2.toString());

try{
PersonInfo p3 = new PersonInfo("Tina", -3, null);
}catch (Exception e) {
System.out.println("p3 happen ex: "+ e.getMessage());
}

PersonInfo p4 = new PersonInfo("Tony");
System.out.println("p4.toString: " + p4.toString());

try{
PersonInfo p5 = new PersonInfo(null);
}catch (Exception e) {
System.out.println("p5 happen ex: "+ e.getMessage());
}

PersonInfo p6 = PersonInfo.of("David");
System.out.println("p6.toString: " + p6.toString());
}
}

figure 1.png

Text Blocks 文本块

JDK17在处理多行字符串方面引入了新特性Text Blocks文本块。该特性使得定义JSON字符串会更简单方便。开始的 “”” 后必须要换行,否则编译失败;结束的 “”” 可以直接写在最后一个字符后,此时文本的最后没有换行符;如果结束的 “”” 单独一行,则文本最后有换行符

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
public class TextBlocksTest {

public static void main(String[] args) {
String line = "###############################";
System.out.println(line);
String jsonStr1 = """
{
"name": "Bob",
"age": 22,
"sex": "woman"
}""";
System.out.println( jsonStr1 );

System.out.println(line);
String jsonStr2 = """
{
"name": "Aaron",
"age": 18,
"sex": "man"
}
""";
System.out.println(jsonStr2);
System.out.println(line);
}
}

figure 2.png

Switch 表达式增强

JDK17中对switch表达式进行了增强:

  • 允许switch表达式有返回值,这样就可以将表达式的结果直接赋值给一个变量
  • 支持箭头语法。即将:冒号替换为->箭头。该语法不仅可以实现一个case中匹配多个值;且不会引发穿透,故无需使用break语句
  • 支持yield关键字。当case块后有多条语句,可使用yield关键字来返回值(相当于return)
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
public class SwitchTest {
public static void main(String[] args) {
foo(3);
foo(1);
foo(2);
foo(6);
foo(69);
foo(996);
foo(18);
}

private static void foo(Integer num) {
String res = switch (num) {
case 1,3,5 -> "Aaron";
case 2,4,6 -> "Bob";
case 69,96,996 -> {
if( num<100 ) {
yield "张三";
}
yield "李四";
}
default -> "GG";
};

System.out.println("[Foo]: "+num+" -->> " + res);
}
}

figure 3.png

instanceof 增强

instanceof 得到增强。将类型判断、变量赋值合并为一步完成。在类型判断后可直接声明类型转换后的变量名,然后直接使用该变量名。无需手动强转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class InstanceOfTest {
public static void main(String[] args) {
foo(18);
foo("Aaron");
}

public static void foo(Object obj) {
if( obj instanceof Integer ) { // 旧写法
Integer num = (Integer)obj;
System.out.println("This is Integer: " + num);
} else if( obj instanceof String str ) { // 新写法
System.out.println("This is str: " + str);
}
}
}

figure 4.png

Stream API增强

Stream从JDK 9开始提供了下述新API

  • takeWhile方法:该方法返回一个流。其会获取满足谓词条件的元素,直到遇到第一个不满足谓词条件的元素后停止获取
  • dropWhile方法:该方法返回一个流。其会丢弃满足谓词条件的元素,直到遇到第一个不满足谓词条件的元素后停止丢弃
  • ofNullable方法:如果提供的元素为null,则返回一个空流。这样无需判空,避免发生NPE
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
33
34
35
36
37
38
39
40
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest {
private static final String separator = "\n#######################";

public static void main(String[] args) {
testTakeWhile();

System.out.println(separator);
testDropWhile();

System.out.println(separator);
testNullable();
}

private static void testTakeWhile() {
Stream.of("a", "b", "c", "", "e", "f", "", "h", "i", "","k")
.takeWhile(StringUtils::isNotBlank)
.forEach(System.out::print);
}

private static void testDropWhile() {
Stream.of("a", "b", "c", "", "e", "f", "", "h", "i", "","k")
.dropWhile(StringUtils::isNotBlank)
.forEach(System.out::print);
}

private static void testNullable() {
List<Integer> nums = null;
Stream.ofNullable(nums).flatMap(List::stream).forEach(System.out::print);

System.out.println(separator);

nums = Arrays.asList(1,3,5);
Stream.ofNullable(nums).flatMap(List::stream).forEach(System.out::print);
}
}

figure 5.png

Optional API增强

Optional从JDK 9开始提供了下述新API

  • stream方法:该方法用于将optional对象转换为stream流。如果optional中的值不为null,则返回一个包含该值的stream流;如果optional中的值为null,则返回一个空流
  • ifPresentOrElse方法:该方法提供了一种条件执行逻辑。其会在optional中的值不为null时执行一个操作;而在optional中的值为null时执行另一个操作。显然相比较于ifPresent方法,该方法更加灵活
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class OptionalTest {

public static void main(String[] args) {
testStream();
testIfPresentOrElseAPI();
}

private static void testStream() {
System.out.println("Test stream API:");

List<String> alpha = null;
Optional<List<String>> optional = Optional.ofNullable(alpha);
optional.stream()
.flatMap(List::stream)
.map(String::toUpperCase)
.forEach(System.out::print);

System.out.println("\n##########################################");

alpha= Arrays.asList("c", "d", "e");
optional = Optional.ofNullable(alpha);
optional.stream()
.flatMap(List::stream)
.map(String::toUpperCase)
.forEach(System.out::print);

}

private static void testIfPresentOrElseAPI() {
System.out.println("\n\nTest ifPresentOrElse API:");

String name = null;
Optional.ofNullable(name)
.ifPresentOrElse(
x -> System.out.println("Hello, I'm "+x),
() -> System.out.println("This is Anonymous")
);

name = "Aaron";
Optional.ofNullable(name)
.ifPresentOrElse(
x -> System.out.println("Hello, I'm "+x),
() -> System.out.println("This is Anonymous")
);
}
}

figure 6.png

请我喝杯咖啡捏~

欢迎关注我的微信公众号:青灯抽丝