你不应该错过的6个伟大的Java新功能

96 阅读6分钟

你不希望错过的6个伟大的Java新功能

要跟上Java频繁发布的特性并不容易。如果你错过了密封类、文本块、记录、新的字符串方法或Optional类,让我们来解决这个问题。

2018年,随着新的发布节奏的采用,Java悄然经历了其发展中最大的变化之一。这个大胆的新计划使得Java开发者每六个月就能得到一个新的功能版本。

这对于保持Java的新鲜感和相关性是非常好的,但这也使得它很容易错过功能的引入。本文综述了几个有用的新特性,并对它们进行了概述。

可选类

空指针异常是所有错误中最经典的一种。虽然它可能很熟悉,但它是一个非常冗长的问题,需要防范。至少在Java 8引入(和Java 10完善)Optional 类之前是这样。

从本质上讲,Optional 类允许你包装一个变量,然后使用包装器的方法来更简洁地处理空值问题。

清单1有一个花园式的空指针错误的例子,其中一个类的引用,foo ,是空的,一个方法,foo.getName() ,被访问。

清单1.没有Optional的空指针

public class MyClass {

Optional 提供了一些处理这种情况的方法,这取决于你的需要。它有一个 方法,你可以用它来做一个if-check。然而,这最终是相当啰嗦的。但是, 也有功能处理的方法。例如,清单2显示了你如何使用 --注意与 有一个字母的区别--只在有数值存在时运行输出代码。isPresent() Optional ifPresent() isPresent()

清单2.只在有值的情况下运行代码

import java.util.Optional;

一个提示:当使用Optional ,如果你使用orElse() 方法通过方法调用提供一个默认值,考虑使用orElseGet() 来代替提供一个函数引用,以获得在值非空时不运行调用的性能优势

记录类(预览功能)

构建Java应用的一个常见需求是所谓的不可变的DTO(数据传输对象)。DTOs用于对来自数据库、文件系统和其他数据存储的数据进行建模。传统上,DTOs是通过制作一个类来创建的,其成员通过构造函数来设置,没有访问它们的getters。Java 14引入了新的record 关键字,并在此基础上进行了改进,它为这一目的提供了速记。

清单3说明了在引入record 类型之前的一个典型的DTO定义和用法。

清单3.一个简单的不可变的DTO

public class MyClass {

如清单4所示,我们可以使用record 关键字来消除大部分的模板。

清单4.使用记录关键字

public class MyClass {

请注意,使用数据对象的客户端代码并没有改变;它的行为就像一个传统定义的对象。record 关键字足够聪明,可以通过简单的定义足迹推断出存在哪些字段。

record 类型也定义了equals(),hashCode(), 和toString() 的默认实现,同时也允许开发者重写这些实现。 你也可以提供一个自定义的构造函数。

注意,记录不能被子类化。

新的字符串方法

在Java 10和Java 12中,增加了几个有用的新String 方法。除了字符串操作方法外,还引入了两个新的方法来简化文本文件访问。

Java 10中的新String 方法:

  • isBlank():如果字符串为空或者字符串只包含白色空间(这包括制表符),则返回真。注意isBlank()isEmpty() 不同,后者只在长度为0时返回真。
  • lines():将一个字符串分割成一个字符串流,每个字符串包含一个行。 行由/r/n/r/n 定义。作为一个例子,考虑下面的清单5。
  • strip(),stripLeading(),stripTrailing(): 分别从开头和结尾、仅开头和仅结尾去除白色空间。
  • repeat(int times):返回一个字符串,该字符串取自原始字符串并重复指定的次数。
  • readString():允许从文件路径直接读取一个字符串,如清单6中所示。
  • writeString(Path path):将字符串直接写到指定路径的文件中。

Java 12中新的String 方法。

  • indent(int level):将字符串缩进到指定的数量。负值只影响前面的空白处。
  • transform(Function f):将给定的lambda应用于字符串。

清单5.String.lines()示例

import java.io.IOException;

清单6.String.readString(Path路径)示例

Path path = Path.of("myFile.txt"); 

开关表达式

Java 12引入了switch 表达式,允许在语句中内联使用switch 。换句话说,switch 表达式会返回一个值。Java 12还提供了一种箭头语法,它消除了对显式break 的需要,以防止落空。Java 13更进一步,引入了yield 关键字,明确表示switch 情况下返回什么值。Java 14将新的switch 表达式语法作为一项完整的功能。

让我们来看看一些例子。首先,清单7有一个传统(Java 8)格式的switch 语句的例子(非常矫揉造作)。这段代码使用一个变量(message)来输出一个数字的名字,如果它是已知的。

清单7.老式的Java开关

class Main { 

现在这段代码相当啰嗦,而且很挑剔。事实上,其中已经有一个错误了!仔细看,有一个缺失的 。仔细观察,有一个缺失的break 。清单8通过使用一个switch 表达式来简化它。

清单8.新的开关表达式

class NewSwitch { 

在清单8中,你可以看到switch 表达式直接放在了System.out.println 调用中。这已经是一个很大的可读性的胜利,并且消除了多余的消息变量。另外,箭头语法通过消除break 语句,减少了代码的占用。(当不使用箭头语法时,使用yield 关键字)。

在这里了解更多关于新的switch 语法的信息。

文本块

Java 13通过引入文本块,解决了在Java中处理复杂文本字符串时长期存在的烦恼。Java 14完善了这种支持。

像JSON、XML和SQL这样的东西会让你为多个嵌套的转义层而疯狂。正如规范所解释的。

在Java中,在字符串字面中嵌入HTML、XML、SQL或JSON片段......通常需要通过转义和连接进行大量的编辑,然后包含该片段的代码才能编译。该代码段通常难以阅读,维护起来也很费劲。

请看清单9,其中新的文本块语法被用来创建一个JSON片段。

清单9.使用文本块的JSON

class TextBlock { 

在清单9中,没有看到一个转义字符。注意三倍的双引号语法。

密封的类

Java 15(JEP 260)引入了密封类的概念。简而言之,新的sealed 关键字允许你定义哪些类可以子类化一个接口。在这种情况下,一个例子胜过千言万语。请看清单10。

清单10.封闭类的例子

public abstract sealed class Pet

在这里,接口设计者使用sealed 关键字来指定哪些类被允许扩展Pet 类。