一起养成写作习惯!这是我参与「掘金日新计划·4月更文挑战」的第1天,点击查看活动详情。
偶尔刷一刷各大中文技术社区,还有很多标题还是“Java 8的新特性”等等,对于一个10年前发布的版本可能真的称不上“新”了。但不可忽视的是,现在业务保有量最大的版本确实还是8,继续深究Java8也完全没问题。没有追捧新技术的意思,但技术在进步,我们也应该打开视野,保有量第二的已经到了11了,虽然11也是LTS,但维护截止日期与8仅差1年,恰好17在2021年9月就正式发布,所以你的下一个版本的最佳选择应该是17。这里就再谈一下Java17正式发布的record类。
什么是Record
Record类在Java14中就开始预览,一直到最近的一个LTS版本——Java17才正式发布。根据JEP395的描述,Record类是不可变数据的载体,类似于当下广泛应用的各种model,dto,vo等POJO类,但record本身在构造之后遍不再可赋值。所有的record类都继承自java.lang.Record
。
Record提供了什么
record类默认提供了全字段的构造器,属性的访问,还有equals,hashcode,toString方法。可能乍一看这不就是lombok吗,或者熟悉kotlin的会觉得这就是data class啊。确实,功能性上区别大不,除了record是不可变的。下面是一个record类型的定义:
record Rectangle(double length, double width) { }
如果用lombok就是下面这样:
@Data
public Rectangle{
private double length;
private double width;
}
两者的区别在于,对于equals,hashcode,toString等方法,record的字节码使用了invokedynamic,而lombok使用的是普通的invokestatic等,性能要比后者高出很多。
Record怎么用
如果仅仅用于传统的POJO类的替换,其实可读性要差很多。因为record默认只提供了全字段的构造器,需要这样写:
Rectangle r = new Rectangle(4,5);
两个字段可能还好点,但通常我们需要10个或者更多的字段时,这种初始化看着就头大。当然,record类支持自定义构造器,也可以支持了一些简化操作,但跟lombok的@Builder还是没法比。是不是就应用用在字段比较少的情况下呢?个人觉得record的一个重要用法就是存储方法内的临时数据对象,举个例子:
public List<Person> sortPeopleByAge(List<Person> people) {
record Data(Person person, int age){};
return people.stream()
.map(person -> new Data(person, computeAge(person)))
.sorted((d1, d2) -> Double.compare(d2.age(), d1.age()))
.map(Data::person)
.collect(toList());
}
public int computAge(Person person) {
return person.getAge();
}
上面的代码是把Person对象按照年龄排序,如果不是record构建一个临时存储对象,需要怎么实现呢,相对来说通过这种流式写法还是比较费劲的。
小结
Record类从性能上说要远比lombok强,毕竟是亲生的。但record类更适合用做方法的临时内部数据存储,可以很大程度上提升可读性。