写点什么

Java 14 将于 3 月 17 日发布,新特性一览

2020 年 3 月 08 日

Java 14将于3月17日发布,新特性一览

Java 14 计划于 3 月 17 号发布。这一版本包含的 JEP 比 Java 12 和 Java 13 的总和还要多。那么,对于每天需要面对 Java 代码的开发者来说,哪些东西最值得关注?


本文将着重介绍以下这些 Java 新特性:


  • 改进的switch表达式。这一特性已经作为预览版出现在Java 12和Java 13中,而Java 14将带来它的完整正式版。

  • instanceof的模式匹配(这是个一语言特性)。

  • 非常有用的NullPointerException信息(这是一个JVM特性)。


switch 表达式


在 Java 14 中,switch 表达式是一个正式的特性。而在之前的两个 Java 版本中,这个特性只是预览版。设定“预览版”的目的是为了收集开发者反馈,并根据反馈结果决定相应的特性是否要做出修改,甚至是移除,但其中的大部分都会成为正式特性。


新的 switch 表达式有助于减少 bug,因为它的表达和组合方式更容易编写。例如,下面的示例使用了箭头语法:


var log = switch (event) {    case PLAY -> "User has triggered the play button";    case STOP, PAUSE -> "User needs a break";    default -> {        String message = event.toString();        LocalDateTime now = LocalDateTime.now();        yield "Unknown event " + message +               " logged on " + now;    }};
复制代码


文本块


Java 13 引入了文本块特性,并将其作为预览版。有了这个特性,处理多行字符串字面量就容易了很多。在 Java 14 中,该特性仍然是预览版,不过做了一些调整。在没有这个特性之前,要表示多行格式化的字符串需要像下面这样:


String html = "<HTML>" +"\n\t" + "<BODY>" +"\n\t\t" + "<H1>\"Java 14 is here!\"</H1>" +"\n\t" + "</BODY>" +"\n" + "</HTML>";
复制代码


有了文本块特性之后,可以使用三引号来表示字符串的开头和结尾,这样的代码看起来更简洁、更优雅:


String html = """<HTML>  <BODY>    <H1>"Java 14 is here!"</H1>  </BODY></HTML>""";
复制代码


在 Java 14 中,该特性增加了两个转义字符。一个是\s,用来表示单空格。一个是反斜杠\,用在行末表示不换行。如果你有一个很长的字符串,为了让代码看起来更好看,但又不希望真的换行,就可以使用这个转义字符。


例如,目前的多行字符串是这样的:


String literal =          "Lorem ipsum dolor sit amet, consectetur adipiscing " +         "elit, sed do eiusmod tempor incididunt ut labore " +         "et dolore magna aliqua.";
复制代码


使用了新的转义字符之后是这样的:


String text = """                Lorem ipsum dolor sit amet, consectetur adipiscing \                elit, sed do eiusmod tempor incididunt ut labore \                et dolore magna aliqua.\                """;
复制代码


instanceof 的模式匹配


为了避免在使用 instanceof 后还需要进行类型转换,Java 14 引入了一个新的预览版特性。例如,在没有该特性之前:


if (obj instanceof Group) {  Group group = (Group) obj;  // 调用group的方法  var entries = group.getEntries();}
复制代码


我们可以使用新的特性来重写这段代码:


if (obj instanceof Group group) {  var entries = group.getEntries();}
复制代码


既然条件检查已经确认 obj 是 Group 类型,那为什么还要再次进行显式的类型转换呢?这样有可能更容易出错。新的语法可以将代码中的大部分类型转换移除掉。2011 年发布的一份研究报告显示,Java 代码中有 24%的类型转换是跟在 instanceof 之后的。


Joshua Bloch 的经典著作《Effective Java》中有一段代码示例:


@Override public boolean equals(Object o) {     return (o instanceof CaseInsensitiveString) &&             ((CaseInsensitiveString) o).s.equalsIgnoreCase(s); }
复制代码


这段代码可以使用新的语法写成:


@Override public boolean equals(Object o) {     return (o instanceof CaseInsensitiveString cis) &&            cis.s.equalsIgnoreCase(s); }
复制代码


这个特性很有意思,因为它为更为通用的模式匹配打开了大门。模式匹配通过更为简便的语法基于一定的条件来抽取对象的组件,而 instanceof 刚好是这种情况,它先检查对象类型,然后再调用对象的方法或访问对象的字段。


记录类(Record)


另一个预览特性是“记录”。该特性主要是为了降低 Java 语法的“啰嗦”程度,让开发者写出更简洁的代码。这个特性主要用在某些领域类上,这些类主要用于保存数据,不提供领域行为。


我们以一个简单的领域类 BankTransaction 作为例子,它包含了三个字段:date、amount 和 description。目前,这个类需要以下几个组件:


  • 构造器;

  • getter方法;

  • toString()方法;

  • hashCode()和equals()方法。


这些方法一般可以通过 IDE 自动生成,但会占用很大的代码空间,例如:


public class BankTransaction {    private final LocalDate date;    private final double amount;    private final String description;

public BankTransaction(final LocalDate date, final double amount, final String description) { this.date = date; this.amount = amount; this.description = description; }
public LocalDate date() { return date; }
public double amount() { return amount; }
public String description() { return description; }
@Override public String toString() { return "BankTransaction{" + "date=" + date + ", amount=" + amount + ", description='" + description + '\'' + '}'; }
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BankTransaction that = (BankTransaction) o; return Double.compare(that.amount, amount) == 0 && date.equals(that.date) && description.equals(that.description); }
@Override public int hashCode() { return Objects.hash(date, amount, description); }}
复制代码


Java 14 提供了一种方式,可以避免这种繁琐的代码,满足开发者希望一个类只是用来聚合数据的意图。BankTransaction 可以重构成:


public record BankTransaction(LocalDate date,                              double amount,                              String description) {}
复制代码


除了构造器和 getter 方法,还会自动生成 equals、hashCode 和 toString 方法。


要尝试这个特性,需要在编译代码时打开预览标签:


javac --enable-preview --release 14 BankTransaction.java
复制代码


记录类的字段隐式都是 final 的,也就是说不能对它们进行动态赋值。不过要注意,这并不意味着整个记录类对象都是不可变的,如果字段保存的是对象,那么这个对象是可变的。


这里要插一句话,如果从培训的角度来讲,例如你要教会初级开发者,那么记录类应该在什么时候讲授比较好?在介绍 OOP 和类的概念之前还是之后?


有用的 NullPointerException 信息


有些人认为,抛出 NullPointerException 应该成为 Java 编程的一个新的“Hello world”,因为这是不可避免的。NullPointerException 确实让人抓狂,它们经常出现在生产环境的日志里,但调试起来很困难。例如,看看下面这段代码:


var name = user.getLocation().getCity().getName();
复制代码


这段代码可能会抛出一个异常:


Exception in thread "main" java.lang.NullPointerException    at NullPointerExample.main(NullPointerExample.java:5)
复制代码


在一行代码里连续调用了多个方法,比如 getLocation()和 getCity(),它们都有可能返回 null,而 user 也可能为 null。所以,我们无法知道是什么导致了 NullPointerException。


在 Java 14 中,JVM 会抛出更多有用的诊断信息:


Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Location.getCity()" because the return value of "User.getLocation()" is null    at NullPointerExample.main(NullPointerExample.java:5)
复制代码


错误信息提供了两个内容:


  • 结果:无法调用Location.getCity()。

  • 原因:User.getLocation()返回值是null。


要启用这个功能,需要添加 JVM 标识:


-XX:+ShowCodeDetailsInExceptionMessages
复制代码


例如:


java -XX:+ShowCodeDetailsInExceptionMessages NullPointerExample
复制代码


据报道,在未来的版本中,这个特性可能会默认启用。


这个增强特性不仅适用于方法调用,只要会导致 NullPointerException 的地方也都适用,包括字段的访问、数组的访问和赋值。


结论


Java 14 带来了一些新的预览特性,例如可用于避免显式类型转换的 instanceof 模式匹配。它还引入了记录类,提供了一种简洁的方式来创建只用于聚合数据的类。另外,增强的 NullPointerException 错误信息有助于更好地进行诊断。switch 表达式成为 Java 14 的正式特性。文本块进入第二轮预览,新增了两个转义字符。


英文原文


Java 14 arrives with a host of new features


2020 年 3 月 08 日 10:007836
用户头像
小智 InfoQ 主编

发布了 397 篇内容, 共 308.6 次阅读, 收获喜欢 1719 次。

关注

评论 10 条评论

发布
用户头像
很多改动并不好
2020 年 04 月 09 日 13:34
回复
用户头像
很棒
2020 年 03 月 22 日 19:49
回复
用户头像
牛逼,都是试用的新特性!
2020 年 03 月 20 日 11:39
回复
用户头像
我要吐了,好🤮的改动!
2020 年 03 月 18 日 14:26
回复
用户头像
一般的scala代码会不会可读性差?
2020 年 03 月 11 日 11:26
回复
用户头像
来学scala啊,这些特性都有,还更强
- match case 模式匹配
- 多行字符串支持对齐
- case class 自带模板代码
2020 年 03 月 09 日 13:00
回复
用户头像
Java 逐渐 Kotlin 化
2020 年 03 月 08 日 17:51
回复
用户头像
8都还没整明白
2020 年 03 月 08 日 16:53
回复
用户头像
不过现在生产环境 , 都还停留在java8 , 估计等用上 java14 得过一段时间.
2020 年 03 月 08 日 10:11
回复
用户头像
这几个特性都非常不错, 挺喜欢的.
2020 年 03 月 08 日 10:10
回复
没有更多了
发现更多内容

第三周作业

丁乐洪

8张图带你分析Redis与MySQL数据一致性问题

Java架构师迁哥

架构师训练营 - 第 7 周课后作业(1 期)

阿甘

科学家联合提出基于区块链的追溯框架

CECBC区块链专委会

区块链 农业

架构师训练营第 1 期 - 第七周作业

Todd-Lee

极客大学架构师训练营

目标检测之YOLOv2

Dreamer

WSL还是不错的

孙苏勇

WSL2 工具链 wsl

Week 7 作业一

黄立

穿越时空的回响:华为欧洲创新日的蝴蝶振翅

脑极体

三、设计模式

Geek_28b526

【涂鸦物联网足迹】涂鸦云平台全景介绍

IoT云工坊

人工智能 云计算 大数据 物联网平台 物联网

区块链usdt承兑商支付系统开发,usdt跑分系统搭建

WX13823153201

极客大学 - 架构师训练营 第七周作业

9527

Week 7 性能优化总结

黄立

在Idea中使用JUnit单元测试

jiangling500

单元测试 IDEA JUnit

查漏补缺:166个最常用的Linux命令,哪些你还不知道?

小Q

Java Linux 程序员 操作系统 开发

架构师训练营第 1 期 - 第七周总结

Todd-Lee

极客大学架构师训练营

架构师训练营 第三周作业(手写单例模式)

springH₂O

架构训练营

架构师训练营 - 第三周课后练习

joshuamai

区块链将颠覆和改变传统金融业底层逻辑

CECBC区块链专委会

区块链 数字经济

week3 代码重构 学习总结

杨斌

架构师训练营 - 第三周学习总结

joshuamai

【涂鸦物联网足迹】物联网主流通信方式

IoT云工坊

人工智能 云计算 大数据 物联网 云平台

架構師訓練營第 1 期 - 第 07 周總結

Panda

架構師訓練營第 1 期

手把手教你如何在Windows安装Anaconda

计算机与AI

Python Anaconda

https 握手失败问题排查全记录

lockdown56

nginx https 网络 HTTP 抓包

GrowingIO 响应式编程探索和实践

GrowingIO技术专栏

响应式编程

区块链追溯系统迎来新突破

CECBC区块链专委会

区块链 溯源 产品溯源

week3 代码重构 -作业一

杨斌

一定要偷偷学,偷偷进步!腾讯内部首发Java多线程、高并发、设计模式“满级”笔记

Java架构追梦

Java 架构 面试 设计模式 多线程与高并发

LeetCode题解:231. 2的幂,位运算取二进制中最右边的1,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

Java 14将于3月17日发布,新特性一览-InfoQ