在Java中正确使用Optional

Optional类是在Java 8中引入的,用于解决NullPointerException的问题。

java.util.Optional类是一个泛型类型的类,只包含一个类型为T的值。其目的是提供对可能为null的类型T的引用对象的更安全的替代方案。但是,只有在正确使用的情况下,Optional对象才是安全的。

创建Optional对象的方式:

Empty Optional

使用Optional.empty(),我们可以创建一个不包含任何类型的空的optional对象。

java 复制代码
//returning a empty optional of type string
public static Optional<String> emptyOptional(){
       return Optional.empty();
}

//or
Optional<String> str = Optional.empty();

Nullable Optional

使用Optional.ofNullable()方法,我们可以创建可空的Optional对象。这些对象可以是null,也可以包含值。

java 复制代码
public static Optional<Wallet> getWallet(){
        return Optional.ofNullable(null);
}

Non-Nullable Optional

使用该Optional.of()方法我们可以创建不可为 null 的可选对象。

java 复制代码
public static Optional<Wallet> getWallet(){
        return Optional.of(new Wallet(100));
}

现在让我们看一下Optional类中的不同方法,我们可以利用这些方法来编写促进空安全的清晰代码。

在Optional类中的 get() 方法用于获取值,如果存在的话,否则抛出NoSuchElementException异常。

例如,假设我们有一个具有私有字段money的Wallet对象。要获取money的值,我们可以按如下方式操作:

java 复制代码
//normal way to get money 
int savings = wallet.getMoney();

//when wallet object is wrapped in a optional 
int savings = optionalWallet.get().getMoney();

如果wallet对象为null,第二种方式比第一种方式更安全,因为它会抛出NoSuchElementException而不是NullPointerException。

我们可以通过使用isPresent()方法来改进第二种方式,该方法返回一个布尔值,指示值是否存在。

java 复制代码
List<Integer> savings = new ArrayList();
if(optionalWallet.isPresent()){
    savings.add(optionalWallet.get().getMoney());
}

但与此同时,这种方式并没有比检查非空更为简洁。

java 复制代码
List<Integer> savings = new ArrayList();
if(wallet != null){
  savings .add(wallet.getMoney());
} 

为了使代码更简洁清晰,我们可以使用ifPresent()方法,该方法接受一个Consumer或一个Runnable,或者两者都接受。使用ifPresent(),我们可以消耗一个正确的值或生成一个替代值。让我们看一下具体的用法。

java 复制代码
List<Integer> savings = new ArrayList();
optionalWallet.ifPresent(wallet -> savings.add(wallet.getMoney()));

在上面的示例中,只有当wallet不为null时,即存在时,才将money添加到savings中。

如果我们将wallet本身添加到列表中。

java 复制代码
//using lambda
List<Wallet> wallets  = new ArrayList<>();
optionalWallet.ifPresent(wallet -> wallets.add(wallet));

//you can also use method reference
List<Wallet> wallets  = new ArrayList<>();
optionalWallet.ifPresent(wallets::add);

正如你所看到的,这比一开始的示例要好得多。

在某些情况下,当optional为空时,你可能希望有一个默认值。使用orElse()方法,我们可以在optional为null时生成一个替代值。让我们看一个例子。

java 复制代码
List<Wallet> wallets  = new ArrayList<>();
Wallet wallet = optionalWallet.orElse(new Wallet(0));
wallets.add(wallet);

在上面的例子中,如果optionalWallet包含一个值,它将被赋给wallet变量;如果没有值,则分配一个值为0的默认wallet。orElse()方法可以与任何其他类型一起使用,生成默认值。

你还可以在orElseGet()方法内调用一块代码来计算一个默认值。

java 复制代码
//calculating a default value 
Wallet wallet = optionalWallet.orElseGet(() -> {
            int randomAmount = (int) (Math.random() * 500); // Generating a random amount between 0 and 500
            return new Wallet(randomAmount);
});

在使用Spring Boot应用程序和数据库时,当我们执行选择查询以获取用户时,一种良好的实践是将用户对象封装在Optional中,然后我们可以这样做:

java 复制代码
//Getting the user from database
Optional<User> findUserById(String id);

//Calling the find user method 
User user = findUserById(id)
                    .orElseThrow(UserNotFoundException::new);

在上面的例子中,你可以看到,我们不需要进行任何检查来确定用户是否存在。如果数据库中存在用户,我们将获取该用户;如果不存在,我们将在那里优雅地抛出一个异常。

相关推荐
程序员清风14 分钟前
阿里二面:Kafka 消费者消费消息慢(10 多分钟),会对 Kafka 有什么影响?
java·后端·面试
幼稚园的山代王14 分钟前
Prompt Enginering(提示工程)先进技术
java·人工智能·ai·chatgpt·langchain·prompt
周某某~23 分钟前
二.单例模式‌
java·单例模式·设计模式
摸鱼仙人~26 分钟前
深入理解Java单例模式:确保类只有一个实例
java·javascript·单例模式
SteveDraw30 分钟前
C++动态链接库封装,供C#/C++ 等编程语言使用——C++动态链接库概述(总)
开发语言·c++·c#·封装·动态链接库
十五年专注C++开发39 分钟前
设计模式之单例模式(二): 心得体会
开发语言·c++·单例模式·设计模式
hstar952742 分钟前
三十五、面向对象底层逻辑-Spring MVC中AbstractXlsxStreamingView的设计
java·后端·spring·设计模式·架构·mvc
flyair_China1 小时前
【云架构】
开发语言·php
pengyu1 小时前
【Java设计原则与模式之系统化精讲:壹】 | 编程世界的道与术(实战指导篇)
java·后端·设计模式
日月星辰Ace1 小时前
JVM 垃圾回收简介
java