春争日,夏争时,扫码抽取夏日礼包!!! 了解详情
写点什么

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

  • 2020 年 3 月 08 日
  • 本文字数:3691 字

    阅读完需:约 12 分钟

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:008062
用户头像
小智 前 InfoQ 主编

发布了 408 篇内容, 共 342.8 次阅读, 收获喜欢 1882 次。

关注

评论 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
回复
没有更多了
发现更多内容

基于磁盘量身定制,十亿规模高效向量检索方案

Zilliz

向量检索 anns 向量计算

技术“开源”对于金融业软件发展的影响

Speedoooo

安全 ios开发 APP开发 Andriod开发 小程序容器

整理了一些JPA常用注解

yombo

Java Spring JPA

60 K8S之EFK日志管理系统

穿过生命散发芬芳

k8s 28天写作 12月日更

揭秘字节跳动基于Hudi的实时数据湖平台

字节跳动数据平台

大数据 实时数据湖

Dubbo 框架学习笔记十七

六维

dubbo 12月日更

谈谈Golang的同步等待组

恒生LIGHT云社区

golang Go 语言

基于DataX的数据同步(下)-应用DataX进行数据同步

恒生LIGHT云社区

数据库 数据同步 DataX

模块八作业

panxiaochun

架构实战营

助车企升级,旺链科技与南方电网、联想等名企同斩获「创新案例奖」

旺链科技

区块链 产业区块链 供应链金融

架构训练营模块三作业

zhongwy

架构实战营 「架构实战营」

面试官:方法重写时需要注意哪些问题?

王磊

实现一键部署与高效集群管理,SphereEx-Boot 正式上线

SphereEx

开源 开源社区 SphereEx ShadingSphere 一键安装

网易有道项目实践技术分享合集

有道技术团队

技术分享 网易有道 技术专题合集

Spring框架基础知识(03)

海拥(haiyong.site)

28天写作 12月日更

seata分布式事务AT模式介绍(二)

恒生LIGHT云社区

分布式 分布式事务 seata

人工智能(NLP)|社交网络中的网络表示学习技术研究

索信达控股

人工智能 算法 网络结构

社区原生的 Go Agent 即将开源

火线安全

DevSecOps IAST

使用亚马逊云科技DevOps 工具构建 InnerSource 生态系统

亚马逊云科技 (Amazon Web Services)

开源 InnerSource

域名基本信息查询小技巧

喀拉峻

网络安全 安全 信息安全

How old are you | 尚硅谷大数据之Canal视频教程

编程江湖

大数据 canal

千万级日志回放引擎设计稿

FunTester

性能测试 测试框架 FunTester 流量回放 GOREPLAY

一次完整的渗透测试&仅供学习研究

H

黑客 网络安全 渗透测试·

☕【权限设计系列】「认证授权专题」微服务架构的登陆认证问题

浩宇天尚

微服务架构 12月日更 权限认证机制 授权设计

一文带你了解数据库安全基础

坚果

数据库 28天写作 12月日更

恒源云(GPUSHARE)_云GPU服务器如何使用SpaCy?

恒源云

gpu 服务器 自然语言

尚硅谷大数据之Canal视频教程发布!

@零度

大数据

Java 14将于3月17日发布,新特性一览_编程语言_Raoul-Gabriel Urma_InfoQ精选文章