目录
传送门
SpringMVC的源码解析(精品)
Spring6的源码解析(精品)
SpringBoot3框架(精品)
MyBatis框架(精品)
MyBatis-Plus
SpringDataJPA
SpringCloudNetflix
SpringCloudAlibaba(精品)
Shiro
SpringSecurity
java的LOG日志框架
Activiti(敬请期待)
JDK8新特性
JDK9新特性
JDK10新特性
JDK11新特性
JDK12新特性
JDK13新特性
JDK14新特性
JDK15新特性
JDK16新特性
JDK17新特性
JDK18新特性
JDK19新特性
JDK20新特性
JDK21新特性
其他技术文章传送门入口
前言
一、instanceof 模式匹配(预览)
instanceof 在新特性中,将类型判断和强制类型转换合二为一,减少了Java程序中显式强制转换的数量
java14之前:
需要先进行类型判断,类型判断为 true 后再手动显示进行强制类型转换
@Test
public void test01() {
Object obj = new String("hello world");
if (obj instanceof String) { // 判断是否为String类型
String string = (String) obj; // 进行强制类型转换
System.out.println(string.toUpperCase());
} else {
System.out.println("这不是一个字符串类型...");
}
}
null 与任何类型进行 instanceof 判断,结果都为 false
java14:
新特性中,将类型判断和强制类型转换合二为一,我们不用再手动显示进行强制类型转换
@Test
public void test02() {
Object obj = new String("hello world");
// 判断是否为String类型,如果是,就将obj强制转换为String类型
// 强制转换后使用string变量接收强制转换后的值
// 将类型判断和强制类型转换合二为一,我们不用再手动显示进行强制类型转换
if (obj instanceof String string) {
System.out.println(string.toUpperCase());
} else {
System.out.println("这不是一个字符串类型...");
}
}
注意:用于接收强制类型转换后的值的变量,只能在 if 的代码块中进行使用,该变量为 if 代码块的局部变量
instanceof 使用小技巧:
class Monitor {
private String model;
private double price;
// public boolean equals(Object o) {
// if (o instanceof Monitor monitor) {
// if (monitor.model.equals(model) && monitor.price == price) return true;
// }
// return false;
// }
// 简写
public boolean equals(Object o) {
// 先判断是否为Monitor类型,是就进行后面的判断,否则直接返回false
// 在后面的判断中可以继续使用 instanceof 判断类型为真的情况下强制类型转换的变量
return o instanceof Monitor monitor && monitor.model.equals(model) && monitor.price == price;
}
}
二、NullPointerException
NullPointerException
● 该特性改进了NullPointerException的可读性,能更准确地给出null变量的信息
● 该特性可以帮助开发者提高生产力,以及改进各种开发工具和调试工具的质量。
● 在JDK14中,新特性可以更好地提示哪个地方出现的空指针,需要通过-XX:+ShowCodeDetailsInExceptionMessages开启
● 这个增强特性不仅适用于方法调用,只要会导致 NullPointerException 的地方也都适用,包括字段的访问、数组的访问和赋值。
● 在后面的版本中,这个特性默认启用
@Test
public void test03() {
String str = null;
str.toLowerCase();
}
// JDK 11 报错描述
java.lang.NullPointerException
at JDK14Test.test03(JDK14Test.java:45)
// JDK 17 报错描述
java.lang.NullPointerException:
Cannot invoke "String.toLowerCase()" because "str" is null
at JDK14Test.test03(JDK14Test.java:45)
三、Record(预览)
1、概念
和枚举类型一样,记录Record也是累的一种受限形式。作为回报,记录对象在简洁性方面提供了显著的好处。
Record
● 没有Record,开发人员想要创建纯数据载体类(plain data carriers)通常都必须编写大量低价值、重复的、容易出错的代码。
● 如:构造函数、getter/setter、equals()、hashCode()以及toString()等。
● 为了避免这种重复代码,Java 14推出 Record
● 使用Record来减少类声明语法,效果类似 lombok 的 @Data 注解,Kotlin中的data class。它们的共同点是类的部分或全部状态可以直接在类头中描述,并且这个类中只包含了纯数据而已。
java14之前javabean:
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (!name.equals(user.name)) return false;
return age.equals(user.age);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age.hashCode();
return result;
}
@Override
public String toString() {
return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
java14的javabean:
idea中new一个class的时候选择Record
新创建的Record如下:
// 相当于上述的User类的代码
// public record Person(String name, Integer age) {}
// 相当于有了构造器 public Person(String name, Integer age) {}
public record Person(String name, Integer age) {
}
Record的使用:
@Test
public void test04() {
Person person = new Person("张三", 23);
System.out.println(person);// Person[name=张三,age=23]
}
Record编译后的字节码:
// 编译后的字节码文件 JDK17
public record Person(String name, Integer age) {
// 构造器
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
// 相当于 getName()
public String name() {
return this.name;
}
// 相当于 getAge()
public Integer age() {
return this.age;
}
}
Record重写了hashCode、equals、toString:
@Test
public void test04() {
Person person1 = new Person("张三", 23);
Person person2 = new Person("张三", 23);
// 重写了 toString 方法
System.out.println(person1);
System.out.println(person2);
// 验证是否重写 equals 方法
// true -> 重写了 equals 方法
System.out.println(person1.equals(person2));
// 验证是否重写 hashCode 方法
// 重写了 hashCode 方法
System.out.println(person1.hashCode()); // 24021582
System.out.println(person2.hashCode()); // 24021582
HashSet<Person> set = new HashSet<>();
set.add(person1);
set.add(person2);
System.out.println(set.size()); // 1
// name() age()
// 相当于 getName() getAge()
System.out.println(person1.name()); // 张三
System.out.println(person2.age()); // 23
}
2、Record 注意点
2.1、核心注意点
在 Record 类中无空参构造器,除非定义 Record 时参数列表为空
当你用record 声明一个类时,该类将自动拥有以下功能:
● 获取成员变量的简单方法,以上面代码为例 name() 和 partner() 。注意区别于我们平常getter的写法。
● 一个 equals 方法的实现,执行比较时会比较该类的所有成员属性
● 重写 equals 当然要重写 hashCode
● 一个可以打印该类所有成员属性的 toString 方法。
● 请注意只会有一个构造方法。
● Record 类为 final
2.2、在Record中可以添加的内容
可以在Record声明的类中定义静态字段、静态方法、构造器或实例方法。
public record Person(String name, Integer age) {
// 可以在Record声明的类中定义静态字段、静态方法、构造器或实例方法。
public static String info = "Person 类";
public static void showInfo() {
System.out.println(info);
}
// 对于不是规范的记录类型的构造器中必须调用规范的记录类型构造器
public Person() {
this("李四", 44);
}
public String nameToUpperCase() {
return name.toUpperCase();
}
}
2.3、在Record中不可以添加的内容
● 不能在 Record 声明的类中定义实例字段,不能声明非静态属性
● 类不能声明为abstract;
● Record 类为 final,不能被继承
● 不能声明显式的父类
● Record 类已经默认继承了 Record
2.4、反射中引入的关于 Record 的方法
在Java.lang.Class对象中添加如下两个新方法:
● RecordComponent[] getRecordComponents()
● boolean isRecord()
四、switch表达式
在JDK12和JDK13中为预览特性,在JDK14中成为正式特性
该特性规定,switch可以当作语句使用,也可以当作表达式使用。
JDK12 中使用->来替代以前的: + break;,并且可以使用一个变量来接收switch表达式的值
JDK13 提供了 yield 来在 block 中返回值
java12之前:
@Test
public void test01() {
String str = "d";
switch (str) {
case "a":
case "b":
case "c":
System.out.println(123);
break;
case "d":
case "e":
System.out.println(45);
break;
case "f":
System.out.println(6);
break;
default:
System.out.println(0);
}
java12:
可以使用->来替代以前的: + break;,并且可以使用一个变量来接收switch表达式的值
@Test
public void test02() {
String str = "e";
// 使用 -> 来替代以前的 : + break;
switch (str) {
// 当 str 为 "a", "b", "c" 其中一个时,输出 123
case "a", "b", "c" -> System.out.println(123);
case "d", "e" -> System.out.println(45);
case "f" -> System.out.println(6);
default -> System.out.println(0);
}
// 可以使用一个变量来接收switch表达式的值
int num = switch (str) {
// 当 str 为 "a", "b", "c" 其中一个时,返回 123
case "a", "b", "c" -> 123;
case "d", "e" -> 45;
case "f" -> 6;
default -> 0;
};
System.out.println(num); // 45
}
java13:
● 可以使用 yield 来在 block 中返回值
● 在 -> 后面可以接一个代码块,可以使用 yield 来在 block 中返回值
用法一:
@Test
public void test03() {
String str = "a";
// 可以使用一个变量来接收switch表达式的值
int num = switch (str) {
// 当 str 为 "a", "b", "c" 其中一个时,返回 123
case "a", "b", "c" -> {
System.out.println("abc");
yield 123;
}
case "d", "e" -> {
System.out.println("de");
yield 45;
}
case "f" -> {
System.out.println("f");
yield 6;
}
default -> {
System.out.println("default");
yield 0;
}
};
System.out.println(num); // 123
}
用法二:
@Test
public void test04() {
String str = "a";
// 使用 : + yield 的写法,全部的分支都要使用该写法
int num = switch (str) {
case "a", "b", "c":
yield 123;
case "d", "e":
yield 45;
case "f":
yield 6;
default:
yield 0;
};
System.out.println(num); // 123
}
五、文本块(预览第二版)
JEP 368:文本块(Text Blocks,第二次预览版)— 文本块作为预览特性首次引入Java 13后收到了众多最终用户的反馈。现在,文本块得到了增强,再次作为预览特性出现在Java 14中,目标成为未来JDK版本的标准特性。使用文本块可以轻松表达跨多行源代码的字符串。它提高了Java程序中以非Java语言编写的代码的字符串的可读性;它约定,任何新构造的文本块都可以用字符串相同的字符集表示,解释相同的转义序列并以与字符串相同的方式进行操作。
文本块
● 文本块在JDK13中第一次引入,在JDK14中进行第二次预览
● 在JDK14中主要是引入了两个转义字符
○ \:表示取消换行
○ \s:表示一个空格操作
● 引入的原因:在Java中,通常需要使用String类型表达HTML,XML,SQL或JSON等格式的字符串,在进行字符串赋值时需要进行转义和连接操作,然后才能编译该代码,这种表达方式难以阅读并且难以维护。
● 引入文本块,可以使得我们可以在多行编写字符串,增加代码可读性
java13之前多行编写字符串:
@Test
public void test1() {
// 代码可读性差
String s = "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Title</title>\n" +
"</head>\n" +
"<body>\n" +
"\n" +
"</body>\n" +
"</html>";
System.out.println(s);
}
打印输出:
java13使用文本块:
@Test
public void test2() {
// 使用文本块编写字符串,输出该字符串时,
// 会保留输出每行最后的换行符
// 代码可读性提高
String s = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>
""";
System.out.println(s);
}
打印输出:
java14使用文本块:
在JDK14中引入了一个新的转义字符 \ ,该转义字符可以用于取消文本块中每行文本最后的换行
@Test
public void test2() {
String s = """
<!DOCTYPE html>\
<html lang="en">\
<head>\
<meta charset="UTF-8">\
<title>Title</title>\
</head>\
<body>\
\
</body>\
</html>\
""";
System.out.println(s);
}
打印输出:
在JDK14中,也引入了另一个转义字符 \s,表示一个空格操作
@Test
public void test2() {
String s = """
select id, name, age\
from t\
where id = 1;\
""";
System.out.println(s);
}
打印输出:
六、弃用ParallelScavenge和SerialOld GC的组合
七、删除CMS垃圾回收器
八、ZGC on macOS和windows
吞吐量
停顿时间