首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

今天 Java 14 正式发布了!放弃 Java 8 行吗?

Java 14今天正式发布了。那么,14版究竟有什么新功能,对于整天写代码、维护代码的Java开发者来说,哪些功能最有用呢?

第14版包含的JEP(Java Enhancement Proposals,Java增强提案)比12版和13版加起来还要多。在这篇文章中,我将主要讨论以下几点:

1、改进的switch表达式,第一次出现在Java 12和13中,在Java 14中获得了完全的支持

2、instanceof支持模式匹配(语言特性)

3、NullPointerException(JVM特性)

希望你在阅读完本文后,积极地代码中实验这些功能,为Java团队提供反馈,并为Java的发展做出贡献。

《New switch Expressions in Java 12》:

https://blogs.oracle.com/javamagazine/new-switch-expressions-in-java-12

《Inside Java 13’s switch Expressions and Reimplemented Socket API》:

https://blogs.oracle.com/javamagazine/inside-java-13s-switch-expressions-and-reimplemented-socket-api

在之前的发布中,switch表达式只是一个“预览”阶段的特性。我想提醒一下,“预览”阶段的特性的目的是为了收集反馈,这些特性可能会随时改变,根据反馈结果,这些特性甚至可能会被移除,但通常所有预览特性最后都会在Java中固定下来。

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中进行第二次预览,而且发生了一些变化。例如,多行文本的格式化可能需要编写许多字符串连接操作和转义序列。下面的代码演示了一个HTML的例子:

String html = "" +

"\n\t" + "" +

"\n\t\t" + "\"Java 14 is here!\"" +

"\n\t" + "" +

"\n" + "";

有了文本块,就可以简化这一过程,只需使用三引号作为文本块的起始和结束标记,就能编写出更优雅的代码:

String html = """

"Java 14 is here!"

""";

与普通的字符串字面量相比,文本块的表达性更好。更多的内容可以参考这篇文章。

《Text Blocks Come to Java》:

https://blogs.oracle.com/javamagazine/text-blocks-come-to-java

例如,现在编写多行字符串的方式如下:

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.\

""";

Java 14引入了一个预览特性,有了它就不再需要编写先通过instanceof判断再强制转换的代码了。例如,下面的代码:

if (obj instanceof Group) {

Group group = (Group) obj;

// use group specific methods

var entries = group.getEntries();

}

利用这个预览特性可以重构为:

if (obj instanceof Group group) {

var entries = group.getEntries();

}

由于条件检查要求obj为Group类型,为什么还要像第一段代码那样在条件代码块中指明obj为Group类型呢?这可能会引发错误。

这种更简洁的语法可以去掉Java程序里的大多数强制类型转换。2011年的一篇针对相关语言特性的研究论文指出,24%的类型转换都来自于instanceof后的条件语句。

《Guarded Type Promotion——Eliminating Redundant Casts in Java》:http://www.cs.williams.edu/FTfJP2011/6-Winther.pdf

JEP 305解释了这项改变,并给出了Joshuoa Bloch的著作《Effective Java》中的一个例子,演示了下面两种等价的写法:

@Override public boolean equals(Object o) {

return (o instanceof CaseInsensitiveString) &&

((CaseInsensitiveString) o).s.equalsIgnoreCase(s);

}

这段代码吗中冗余的CaseInsensitiveString强制类型转换可以去掉,转换成下面的方式:

@Override public boolean equals(Object o) {

return (o instanceof CaseInsensitiveString cis) &&

cis.s.equalsIgnoreCase(s);

}

换句话说,该预览功能仅仅是个开始,以后该功能肯定能够减少更多的代码冗余,从而降低bug发生的可能性。

另一个预览功能就是record。与前面介绍的其他预览功能一样,这个预览功能也顺应了减少Java冗余代码的趋势,能帮助开发者写出更精准的代码。Record主要用于特定领域的类,它的位移功能就是存储数据,而没有任何自定义的行为。

我们开门见山,举一个最简单的领域类的例子:BankTransaction,它表示一次交易,包含三个字段:日期,金额,以及描述。定义类的时候需要考虑多个方面:

构造器

getter方法

toString()

hashCode()和equals()

这些部分的代码通常由IDE自动生成,而且会占用很大篇幅。下面是生成的完整的BankTransaction类:

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提供了一种方法可以解决这种冗余,可以更清晰地表达目的:这个类的唯一目的就是将数据整合在一起。Record会提供equals、hashCode和toString方法的实现。因此,BankTransaction类可以重构如下:

public record BankTransaction(LocalDate date,

double amount,

String description) {}

通过record,可以“自动”地得到equals,hashCode和toString的实现,还有构造器和getter方法。

要想尝试这个例子,需要用preview标志编译该文件:

javac --enable-preview --release 14 BankTransaction.java

record的字段隐含为final。因此,record的字段不能被重新赋值。但要注意的是,这并不代表整个record是不可变的,保存在字段中的对象可以是可变的。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200320A06HOW00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券