项目快速集成Java 17

IDEA 集成 Java 17
亚马逊的Corretto JDK 17 、Zulu JDK 17 都已经加入了豪华午餐。
IDEA默认解压到Windows当前用户文件夹路径下(这里的是C:\Users\fcsca.jdks),之所以解压到.jdks下是因为IDEA的下载目标文件夹就是这个文件夹,方便IDEA自动检出。
解压完成的效果
这里不需要重新配置Java环境变量,都是项目级别的Java版本控制,不会对其它项目造成影响。
然后新建一个Maven项目(也可以是普通项目或者Gradle项目),这个时候还需要配置项目的语言级别等。
语言级别
调整JDK的语言级别为Java 17 ,在IDEA下按快捷键 Ctrl+Alt+Shift+S 呼出下面的对话框并将Language Level修改为17。

修改项目 JDK Level
字节码版本
编译器的字节码版本也需要调整为17。在IDEA中按下快捷键 Ctrl+Alt+S 在图示中的位置进行修改。
修改编译器的字节码版本
Record Class
搞定了环境配置后,开始试一试一个最直观的、也相当有用的语法糖Record。
准确地说这不属于Java 17的新特性,最早在Java 14 中出现,在Java 16中转为正式特性。不过作为LTS版本,这依然是很重要的一个概念。
直观一些,一个数据类传统的写法是:
public class MyRecord {private final String username;private final Integer age;public MyRecord(String username, Integer age) {this.username = username;this.age = age;}public String username() {return username;}public Integer age() {return age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;MyRecord oldRecord = (MyRecord) o;return Objects.equals(username, oldRecord.username)&& Objects.equals(age, oldRecord.age);}@Overridepublic int hashCode() {return Objects.hash(username, age);}@Overridepublic String toString() {return "MyRecord[" +"username='" + username + '\'' +", age=" + age +']';}}
用Record就可以简化为:
public record MyRecord(String username,Integer age) {}
这样大大减少了一些模板代码,让逻辑更加清晰简单。一定意义上代替了Lombok。
Record 是不可变的
Record被用来设计传输不可变的数据。从上面的例子可以看到,一个Record类被初始化后里面的属性是不能改变的,没有Setter方法而是通过全参数构造来初始化数据,天然线程安全。
Record的超类
所有用Record关键字声明的类都是java.lang.Record的子类,这一点有点像枚举。
public abstract class Record {protected Record() {}@Overridepublic abstract boolean equals(Object obj);@Overridepublic abstract int hashCode();@Overridepublic abstract String toString();}
从这里也可以看出所有Record的实现都覆写了equals、hashCode、toString三个方法。
如何判断一个类是Record类?
传统方法:
Record.class.isAssignableFrom(MyRecord.class)
JDK提供了一个新的方法来解决这个问题:
MyRecord.class.isRecord()
值得一提的是Class类还提供了getRecordComponents来获取Record类的成员属性信息。
RecordComponent[] recordComponents = MyRecord.class.getRecordComponents();
Record无法使用extends关键字
由于Record类的唯一的隐式超类是java.lang.Record,Java不支持多继承,使用 extends 显式定义会导致编译错误。
无法定义额外的成员变量
Record类的成员变量只能通过构造声明。所以下面这种写法是错误的:
public record MyRecord(String username,Integer age) {privite String gender;}
定义方法时需要小心
定义方法比较开放,但是请确保定义的方法不会破坏Record不可变的含义。不推荐定义Setter方法。
另外注意Record类的Getter方法不是setXXXX格式的。
使用注解
唯一需要注意的是,在Record类的成员变量上使用注解可能会作用的Getter方法上。就像这样:
public record MyRecord(@Deprecated String username,Integer age) {}
编译后:
public record MyRecord(String username, Integer age) {public MyRecord(@Deprecated String username, Integer age) {this.username = username;this.age = age;}public String getUsername() {return this.username;}/** @deprecated */@Deprecatedpublic String username() {return this.username;}public Integer age() {return this.age;}}
具体的作用域需要根据注解上的@Target元注解的定义域来判定。
