在Java 8的Optional中抛出异常

2023/07/03

1. 概述

在本教程中,我们将介绍如何在Optional为空时抛出自定义异常。

2. Optional.orElseThrow

简单地说,如果该值存在,则isPresent()将返回true,而调用get()将返回该值。否则,它会抛出NoSuchElementException。

还有一个方法orElseThrow(Supplier<? extends X> exceptionSupplier)允许我们提供一个自定义的Exception实例。只有存在时,此方法才会返回值。否则,它将抛出由提供的Supplier创建的异常。

3. 当值丢失时抛出异常

假设我们有一个返回可为空结果的方法:

public String findNameById(String id) {
    return id == null ? null : "example-name";
}

现在我们将调用我们的findNameById(String id)方法两次,并使用ofNullable(T value)方法用Optional包装结果。

Optional提供了一个用于创建新实例的静态工厂方法,这个方法叫做ofNullable(T value),然后我们可以调用orElseThrow。

我们可以通过运行此测试来验证行为:

@Test
public void whenIdIsNull_thenExceptionIsThrown() {
    assertThrows(InvalidArgumentException.class, () -> Optional
        .ofNullable(personRepository.findNameById(null))
        .orElseThrow(InvalidArgumentException::new));
}

根据我们的实现,findNameById返回null。因此,InvalidArgumentException将从orElseThrow方法中抛出。

我们可以使用非空参数调用此方法。然后,我们不会得到InvalidArgumentException:

@Test
public void whenIdIsNonNull_thenNoExceptionIsThrown() {
    assertAll(() -> Optional
        .ofNullable(personRepository.findNameById("id"))
        .orElseThrow(RuntimeException::new));
}

4. 当值存在时抛出异常

正如我们之前提到的,orElseThrow()返回包装的值(如果它存在),否则抛出提供的异常。

现在,让我们看看当包含的值存在时如何抛出异常。

4.1 Optional.ifPresent()

简而言之,这个方法允许我们在Optional的值不为null时执行特定的代码

例如,让我们看看如果我们找到具有特定id的User,如何使用此方法抛出自定义异常

首先,让我们创建UserFoundException异常:

public class UserFoundException extends RuntimeException {

    public UserFoundException(String message) {
        super(message);
    }
}

这里的基本思想是当findById()方法返回带有非空User对象的Optional时抛出UserFoundException

接下来,我们将创建另一个方法,该方法使用Optional的ifPresent()方法来抛出我们的自定义异常UserFoundException:

public void throwExceptionWhenUserIsPresent(String id) {
    this.findById(id)
        .ifPresent(user -> {
            throw new UserFoundException("User with ID: " + user.getId() + " is found");
        });
}

现在,让我们创建一个测试用例来确认当包装的User存在时会引发我们的自定义异常:

@Test
void givenExistentUserId_whenSearchForUser_thenThrowException() {
    final UserRepositoryWithOptional userRepositoryWithOptional = new UserRepositoryWithOptional();
    String existentUserId = "2";

    assertThrows(UserFoundException.class, () -> userRepositoryWithOptional.throwExceptionWhenUserIsPresent(existentUserId));
}

我们还需要确保如果没有User可返回,则不会抛出UserFoundException:

@Test
void givenNonExistentUserId_whenSearchForUser_thenDoNotThrowException() {
    final UserRepositoryWithOptional userRepositoryWithOptional = new UserRepositoryWithOptional();
    String nonExistentUserId = "8";

    assertDoesNotThrow(() -> userRepositoryWithOptional.throwExceptionWhenUserIsPresent(nonExistentUserId));
}

这种方法的唯一限制是我们丢失了包含的User-ifPresent()接收一个Consumer,但不返回任何内容

5. 总结

在这篇简短的文章中,我们讨论了如何从Java 8 Optional中抛出异常。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章