你不希望错过的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 类。