最新实战案例锦集:《Spring Boot3实战案例合集》持续更新,每天至少更新一篇文章,订阅后将赠送文章最后展示的所有MD文档(学习笔记)。
环境:SpringBoot3.2.5
1. 简介
在Java开发中,处理空值往往是一个令人困扰的问题。空值不仅可能导致NullPointerException,还会引发复杂的if条件判断和易错的逻辑。幸运的是,Java 8引入了Optional类,它提供了一种简洁而强大的处理空值的方法,同时提升了代码的质量。Optional作为一个容器对象,可以包含或不包含非空值,并提供了一系列实用的方法来操作其内容。本文将深入探讨 Optional 在Java中的多种应用场景,并展示如何利用这个强大的类来编写更加清晰、表达力强且健壯的代码。
现在,让我们通过几个具体的例子来详细了解 Optional 的使用方法。
2. 实战案例
2.1 处理NPE
Optional 最常见的用例之一是避免NullPointerException。通过将一个可能为null的值包裹在 Optional 中,你可以安全地访问该值而不必担心会出现 NullPointerException。例如,如果你有一个方法返回的值可能是null,你可以改为返回一个Optional,并使用Optional 的方法来安全地访问该值。
String value = null ;
Optional<String> opt = Optional.ofNullable(value) ;
if (opt.isPresent()) {
System.err.println(opt.get()) ;
}
该示例中,我们从一个可能为空的值创建了一个 Optional。然后,我们使用 Optional.isPresent() 方法检查该值是否存在,并使用 Optional.get() 安全地访问该值。
2.2 处理异常
Optional 的另一个引人注目的用例是简化异常处理。你可以使用 Optional.orElseThrow() 方法在值不存在时抛出异常。这可以使代码更简洁、更易读,尤其是在处理多个潜在异常时,如下示例:
Optional<String> opt = Optional.empty() ;
String value = opt.orElseThrow(() -> new RuntimeException("没有数据!")) ;
我们创建了一个空的 Optional,并使用 Optional.orElseThrow() 在值不存在时抛出 RuntimeException。这简化了异常处理代码,使其更加简洁易读。
2.3 延迟处理错误
Optional 也非常适合延迟决定需要发生的事情,以防在更高的上下文中出现错误。现在不是由函数决定行为,而是由调用者决定在调用者的上下文中什么是最好的。
假设我们有一种方法,可以根据图书的 ISBN 在图书馆中搜索图书:
private final BookRepository bookRepository ;
public static Book queryBookByIsbn(String isbn) {
Book book = bookRepository.queryByIsbn(isbn) ;
if (book != null) {
return book ;
} else {
throw new IllegalArgumentException(String.format("未找到【%s】对应的图书", isbn));
}
}
如果查询不到给定 ISBN 的图书,该方法会抛出异常。如何处理这个错误由方法本身决定。那么我们可以使用 Optional 将错误处理延迟给调用者:
public static Optional<Book> queryBookByIsbn(String isbn) {
Book book = bookRepository.queryByIsbn(isbn) ;
if (book != null) {
return Optional.of(book);
} else {
return Optional.empty();
}
}
// 调用
Optional<Book> book = bookService.queryBookByIsbn("SN001") ;
if (book.isPresent()) {
// TODO
} else {
System.err.println("查无此书");
}
如果查询不到给定 ISBN 的图书,该方法会返回一个空的Optional,表示发生了错误。否则,它将返回一个包含Book的Optional。
2.4 链式操作
我们还可以使用 Optional#flatMap() 方法对 Optional 进行链式处理。这对于访问嵌套在其他对象中的值非常有用。例如,如果一个对象包含另一个可能为空的对象,则可以使用 Optional.flatMap() 访问嵌套的值,而不必冒出现 NullPointerException 的风险,如下示例:
Optional<Author> opt = Optional.ofNullable(book)
.flatMap(Book::getAuthor) ;
这样既简化了代码,又避免了空值检查。
2.5 定义默认值
Optional 也可用于定义缺失值或空值的默认值。可以使用 Optional.orElse() 来指定在 Optional 为空时返回的默认值。这可以使你的代码更有弹性,并减少因空值或缺失值导致错误的可能性。
String value = null ;
String result = Optional.ofNullable(value)
.orElse("default") ;
这使得代码更有弹性,并避免了因空值或缺失值导致的错误。
2.6 避免模板代码
通过使用 Optional,可以避免编写检查空值的模板代码。Optional 提供了一种简洁而富有表现力的方法来处理空值,从而使代码更具可读性和可维护性,如下示例:
String value = null ;
Optional<String> opt = Optional.ofNullable(value) ;
String result = opt.map(s -> s.toUpperCase())
.orElse("default") ;
这样就不需要 if 语句来检查 null,使代码更加简洁易读。
2.7 组合方法
Optional 可用于更简洁、更有表现力地将方法组合在一起。通过用 Optional 封装方法的返回值,可以使用 Optional 方法将多个方法的调用串联起来。这可以使代码更易读、更易懂,如下示例:
Optional<String> opt = Optional.of("Pack")
.map(s -> s.toUpperCase())
.filter(s -> s.startsWith("P")) ;
这样,我们就可以在一个表达式中将多个方法调用组合在一起。
2.8 集合处理
Optional 可用于以更简洁、可读性更强的方式处理 Optional 值集合。例如,如果你有一个可选值集合,可以使用 Optional.stream() 创建一个非空值流,然后使用流方法对这些值执行操作。这样可以使代码更具表现力,也更容易理解,如下示例:
List<Optional<String>> list = Arrays.asList(
Optional.empty(),
Optional.of("Pack"),
Optional.of("Zak")
);
String result = list.stream()
.flatMap(Optional::stream)
.collect(Collectors.joining(",")) ;
我们创建了一个 Optional 列表,使用 Optional.stream() 创建了一个非空值流,然后使用stream方法将非空值连接成一个字符串。这样,我们就可以更优雅、处理 Optional 值集合。
2.9 简化配置
Optional 可为配置参数提供默认值,从而简化配置管理,如下示例:
@Value("${app.title}")
private String title ;
String value = Optional.ofNullable(title)
.orElse("Default Title") ;
这使得配置更具弹性,并避免了因配置参数缺失而导致的错误。
2.10 默认实现
Optional 可用于为可能未实现的方法提供默认实现。这可以通过提供默认行为来简化代码,必要时可以重载默认行为,如下示例:
public interface UserService {
default Optional<User> getUser(){
return Optional.empty() ;
}
}
在本例中,我们定义了一个接口,为返回可选值的方法提供默认实现。这就简化了接口的实现,并提供了一种默认行为,必要时可以重写。
2.11 增强可读性
通过提供一种简洁明了的方法来处理空值,Optional 可以用来提高代码的可读性。例如,可以使用 Optional 方法更优雅地处理空值,而不是使用 if 语句编写检查空值的代码。这样可以使代码更易读、更易懂,如下示例:
Optional.ofNullable(value)
.ifPresentOrElse(
v -> todo(v),
() -> todoElse()
) ;
在本例中,我们从一个潜在的空值创建一个 Optional,并使用 Optional.ifPresentOrElse() 在值存在时执行一个操作,在值不存在时执行另一个操作。这提供了一种简洁明了的方法来处理空值,并使代码更具可读性和可维护性。
2.12 处理复杂对象
Optional 可用于处理包含可选值的复杂对象。这可以使你的代码更具弹性,更易于维护,如下示例:
Optional<Color> opt = Optional.ofNullable(square)
.map(Square::upperLeft)
.map(ColoredPoint::color) ;
通过map方法能非常方便的处理数据。
以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
推荐文章
进阶!@ConfigurationProperties注解高级用法你知道吗?
基于SpringBoot通过3种方式轻松搞定敏感字段加密处理
玩转Redis!非常强大的Redisson分布式集合,少写60%代码
SpringBoot3第三方接口调用10种方式,最后一种你肯定没用过