Java17 新特体验 - Rerocd class 篇(扔掉大部分重复的手写 getter/setter)

/

你是否因为 Java11 的新特性不够吸引人,还是 jigsaw 模块化工程模块难度太大,内嵌 httpclient 好用的,但是就是要用 okhttp 发请求。还就是被吐槽的最多的收费问题(oracle 官方主导维护的 openjdk 已经给绝大部份的 javaer 指名方向了呀)。还是你发任你发,我用 Java8 的用户都看过来

现在 Java17 也计划在 2021/9/14 正式发布了。 里面的新特性还是不少的的,比如 zgc(号称能把 GC 时的 stop world 的时间控制在 10ms 内,g1 真是命运多舛),或者是文本块,又或者是更优雅的 switch case 写法。当然最大的特性肯定对编码最有直观变化的 record class 了,真可谓是相见恨晚呀

为啥需要 Record class

  • 其它语言都有了,Java 也要有
  • 手动生成 getter/setter 太费事了,语法啰嗦
  • boolean 到底要不要在属性上加 is
  • 为啥 POJO 类还要实现 toString() equals() 和 hashCode()
  • 为啥 POJO 类为啥要保留无参构造方法
  • lombok 褒贬不一,不利于我大 Java 的内部和谐统一
  • 那些在 POJO 类 getA 但是返回的 B 的值的,到底是要干吗?getter 不是这样用的呀
  • Gson 能序列化的 jackson 不一定行
  • 还有很多被诟病的

Record class 快速上手

Java 因为并没有直接编译为操作系统可以直接调用的二进制可执行文件,所以很多语法特性实现起来相对比较简单,这次的 record class 和 try-resource 的语法糖类是都是在编译过程中修改特定位置的代码就行了,jvm 底层可能都不用关心新的语法规则

声明 record class 通过 record 这个关键字就可以了

比如 Java14 以前的 POJO 都得这样写

  1. public class Article {
  2. private String title;
  3. private String content;
  4. private Long authorId;
  5. public String getTitle() {
  6. return title;
  7. }
  8. public void setTitle(String title) {
  9. this.title = title;
  10. }
  11. public String getContent() {
  12. return content;
  13. }
  14. public void setContent(String content) {
  15. this.content = content;
  16. }
  17. public Long getAuthorId() {
  18. return authorId;
  19. }
  20. public void setAuthorId(Long authorId) {
  21. this.authorId = authorId;
  22. }
  23. }

但 Java14 开始提供的 record class 就大的缩小了代码的篇幅

  1. public record MyFirstRecordClass(String title, String content, Long authorId) {
  2. }

看上去是不是挺优雅的?

看看 javac 到对对我着我们这个新的代码怎么转换的

javac MyFirstRecordClass.java && javap -p MyFirstRecordClass.class

javap 输出内容

  1. Compiled from "MyFirstRecordClass.java"
  2. public final class MyFirstRecordClass extends java.lang.Record {
  3. private final java.lang.String title;
  4. private final java.lang.String content;
  5. private final java.lang.Long authorId;
  6. public MyFirstRecordClass(java.lang.String, java.lang.String, java.lang.Long);
  7. public final java.lang.String toString();
  8. public final int hashCode();
  9. public final boolean equals(java.lang.Object);
  10. public java.lang.String title();
  11. public java.lang.String content();
  12. public java.lang.Long authorId();
  13. }

可以看出来 record class 已经被转为了 final 类,且只能够通过构造器进行初始化属性,及 record class 并没有自动生成 getter/setter,而是使用了与属性名称相同的方法作为访问对象成员的方式,当然你也可以自己再提供一个 getContent() 然后返回 title 的值,如果想早点下班,就不要这样干了。toString() hashCode() equals() 也帮你重写好了,所以以后即使没有 ide 也可以写 java 的 VO 类

Record class 潜在的问题

看上去,的确用 Java14 以后的程序员应该可以提前下班了吗?(答案肯定不是的,加班的理由重来不是什么代码写的太慢吧)

Record class 上手一段时间后其实发现问题还是不少的,或许更多应该是没有按照 record class 的最佳实践

  1. final 强迫这个类运行时不能被修改,所以用的运行时切面,比如事物@Transactional ,缓存@Cacheable@Around 这些类都要罢工了,诸如这样的类不能用 record
  2. 普通的响应类字段太多了,完全通过构造器初始化,字段顺序容易出错
  3. 使用 getter/setter 进行序列化的工具都得罢工了

Record class 与 lombok 的优劣对比

先说结论, record 从各个方面都是优于 lombok 的实现的。 record class 声明的类属于 Immutable class 及 Java14 开始终于有更简洁明了的声明一旦初始化后,就无法变更的对象了。从语法层面去规避了程序的不可控性,不再是一个对象到处都在被 setter 都不清楚最终的具体值是什么。

lombok 优势也很明显,就是对 java 代码友好,也不会有 record class 这样的对序列化工具的不兼容的变更,lombok 更向是对 java 遗留的问题进行修修补补,加上其庞大且复杂的注释体系势必会劝退一部分用户

从技术实现上来说二者差别并不大,都是在编译过程修改生成的 class 文件,最大区别就是 record class 官方的实现,而 lombok 是社区实现的

可以在生产环境使用了吗?

record class 香,但是还是要考虑历史进程的,目前有些工具还不支持,比如熟悉 Gson,而 Jaskson 也需要额外配置。
所以如果一定要用可以先小范围的使用,等到 java 17 被大规模使用的时候再在生产环境使用得。服务端技术要求的稳,而不是新。

参考内容

转载请注明作者和出处,并添加本页链接。
原文链接: //xiaochun.zrlog.com/java17-record-class.html