文章目录
- Java14概述
- 语法变化:instanceof
- 语法变化:switch表达式
- 语法变化: 文本块的改进
- 语法变化: Records记录类型
- Records限制
- Records额外的变量类型
Java14概述
Oracle在2020年3月17日宣布JAVA14 全面上市,JAVA14通过每六个月发布一次新功能,为企业和开发人员社区提供增强功能,继续了Oracle加快创新的承诺。最新的JAVA开发工具包提供了新功能。其中包括两项备受期待的新预览功能:实例匹配的匹配模式(JEP 305) 和记录(JEP 359)以及文本块的第二个预览(JEP 368)。此外,最新的JAVA版本增加了对switch表达式的语言支持,公开了用于持续监控JDK Flight Recorder数据的新API,将低延迟的Z垃圾收集器的可用性扩招到了macOS和Windows,并在孵化器模块中添加了包装完备的java应用程序和新的外部内存访问API,以安全高效的访问JAVA对外部的内存。
可以在openjdk官网中观察到JDK14发布的详细官方计划和具体新特性详情,地址如下
https://openjdk.java.net/projects/jdk/14/
JAVA14 一共发行了16个JEP(JDK Enhancement Proposals,JDK 增强提案)
具体新增特性的介绍:
语言特性7项目:
- switch表达式(标准)
- 友好的空指针异常
- 非易失性字节缓冲区
- record
- instanceof模式匹配
- 文本块改进 二次预览
- 外部存储API
垃圾回收调整:
- G1的NUMA内存分配优化
新增工具:
- JAVA打包工具 孵化
- JFR事件流
增加废弃和移除:
- MacOS系统上的ZGC试验
- windows系统上的ZGC实验
- 弃用Parallel Scavenge 和Serial Old垃圾收集算法
- 弃用Solaris和SPCRC端口
- 移除CMS垃圾收集器
- 删除Pack200工具和API
语法变化:instanceof
以往使用instanceof运算符都是先判断,然后在进行强转,例如我们查看String的equals方法源码.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
// 先进行类型的判断
if (anObject instanceof String) {
// 然后进行强转
String aString = (String)anObject;
if (!COMPACT_STRINGS || this.coder == aString.coder) {
return StringLatin1.equals(value, aString.value);
}
}
return false;
}
需要先判断类型,然后强转,还要声明一个本地变量,语法比较麻烦,比较理想的状态是,在执行类型检测的时候同时执行类型转换。
JEP305 新增了使instanceof运算符具有匹配的能力。模式匹配能够是程序的通用逻辑更加简洁,代码更加简单,同时在做类型判断和类型转换的时候也更加安全。
JAVA14 提供了新的解决方案: 新的instanceof模式匹配,新的模式匹配语法是: 在instanceof的类型之后添加了变量。如果对obj的类型检查通过,obj会被转换成后面的变量表示的数据类型。
Object obj ="hello java";
if(obj instanceof String str){
System.out.println(str);
}else{
System.out.println("not a String");
}
上述语法的判断逻辑时,如果obj是String类型,则会转换为后面的str;如果不是,则执行else。注意,此时的str仅仅是if语句块里的局部变量,在else语句块中不可用。
语法变化:switch表达式
java的Switch语句是一个一直在变化的语法,可能是因为之前的不够强大,在JAVA14中依然可以看到对于switch的语法优化。
简单整理一下switch语句在各个版本中的特点:
版本 | 特性 |
---|---|
JAVA5 | switch变量类型可以使用枚举 |
JAVA7 | switch变量类型可以使用String |
JAVA11 | switch语句可以自动省略break导致的贯穿提示警告 |
JAVA12 | switch语句可以作为表达式,用变量接收结果,可以省略break |
JAVA13 | switch中可以使用yield关键字停止switch语句块 |
JAVA14 JEP361switch表达式(标准)是独立的,不依赖于JEP 325 和 JEP 354,也就是说这里开始,之前学习的switch语句的语法成为一个正式的标准。
JDK12对缺省break的贯穿弱点进行了改进,case: 改成 case L -> ,这样即使不写也不会贯穿了,而且可以作为表达式返回结果
var grade ="a";
var res =switch(grade){
case "a" -> "优秀";
case "b" -> "良好";
case "c" -> "一般";
case "d" -> "及格";
default -> "no such grade";
}
JAVA12 开始也可以进行多值匹配的支持
var grade ="a";
var res =switch(grade){
case "a","b" -> "优秀";
case "c" -> "一般";
case "d" -> "及格";
default -> "no such grade";
}
JAVA13开始可以使用 yield返回结果,这里的case后面仍然是:
String x = "3";
int i = switch (x) {
case "1":
yield 1;
case "2":{
System.out.println("");
yield 2;
}
default:
yield 3;
};
System.out.println(i);
语法变化: 文本块的改进
文本块是在JAVA13中开始了第一次的预览,目标是在字符串中可以更好的表达 HTML XML SQL或者JSON格式的字符串,减少各种的不相关一些空格换行符号,字符串转义和字符串加号的拼接,在JAVA14中,增加了两个escape sequence ,分别是 \ <line-terminator>(取消换行操作) 与\s escape sequence(增加空格),文本块进行了第二次预览,进一步调了JAVA程序书写大段字符串文本的可读性和方便性。
String textBlock= """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>\s\
<body>
</body>\s
</html>
""";
System.out.println(textBlock);
语法变化: Records记录类型
通过Record增强java编程语言,Record提供了一种紧凑的语法来声明类,这些类是浅层不可变数据的透明持有者。
我们经常听到这样的抱怨:“JAVA太冗长”,“JAVA规矩多”。最明显的就是最为简单数据载体的类,为了写一个数据类,开发人员必须编写许多低价值、重复、且容易出错的代码,构造函数
、getter/setter访问器 、equals、hashcode,、toString 这些东西,尽管IDE可以提供一些插件和手段优化,但是仍然没有改变这些代码依然存在。
Record是java的一种新的类型,同枚举一样,Record也是对类的一种限制。Record放弃了类通常享有的特性:将API和表示解耦,但是作为回报,record使数据类型变得非常简洁,一般可以帮助我们定义一些简单的用于传递数据的实体类。
一个record具有名称和状态描述,状态描述声明了record的组成部分:
record Person(String name ,int age){}
因为record在与以上是数据的简单透明持有者,所以record会自动获取很多的标准成员
- 状态声明中的每个成员,都是一个private final的字段,属性设置值则不可修改
- 状态声明中的每个组件的公共读取访问方法,该方法和组件具有相同的名字,get方法和属性名一致
- 一个公共的构造函数,其签名与状态声明相同,构造方法和签名合二为一
- equals和hashcode的实现
- toString的实现
- record提供的默认是一个全参的构造器
测试代码如下
public class Test2 {
public static void main(String[] args) {
Person p =new Person(1,"张三",10);
Person p2 =new Person(1,"张三",10);
System.out.println(p.pname());
System.out.println(p);
System.out.println(p.hashCode());
System.out.println(p2.hashCode());
System.out.println(p.equals(p2));
}
}
record Person(Integer pid,String pname ,Integer page){};
Records限制
records类是隐含的final类,并且不是抽象类,records不能拓展任何类,不能被继承,声明的任何其他字段都必须是静态的。
Records额外的变量类型
可以显示声明从状态描述自动派生的任何成员,可以在没有正式参数列表的情况下声明构造函数,并且在正常的构造函数主体正常完成是调用隐式初始化,这样就可以在显示构造函数中仅执行其参数的验证逻辑,并且省略字段的初始化。
package com.msb.test;
import java.util.Objects;
public class Test2 {
public static void main(String[] args) {
Person p =new Person(1,"张三",10);
Person p2 =new Person(1,"张三",10);
System.out.println(p.pname());
System.out.println(p);
System.out.println(p.hashCode());
System.out.println(p2.hashCode());
System.out.println(p.equals(p2));
}
}
record Person(Integer pid,String pname ,Integer page){
// 定义额外的变量必须是静态的,不能定义成员变量
private static String name;
public static void setName(String name){
Person.name=name;
}
// 可以定义其他实例方法
public void eat(){
System.out.println("eat");
}
// 可以定义其他静态方法
public static void methodA(){
System.out.println("methoA");
}
// 这里是构造函数,默认就是全参的构造函数,和record声明的参数列表是一致的,
// 这里可以使用全参构造函数中的所有参数
// 在这里会默认执行参数给属性赋值操作,就是在这里默认会有this.pid=pid,this.pname=pname,this.page=page
public Person{
System.out.println(pid);
System.out.println(pname);
System.out.println(page);
}
};