Optional当返回值为null时不抛出异常

问题描述 投票:0回答:5

我正在学习Spring Boot,当服务在数据库中找不到项目时,我试图抛出异常,因此,我尝试使用可选,但当我测试它时,除了异常之外,我只得到空响应

    @GetMapping(value = "/compras", produces = "application/json")
public Optional<Compras> retrieveAllCompras(@RequestParam String id) {
    return Optional.of(compraRepository.findById(id)).orElseThrow(RuntimeException::new);

当在数据库中找不到该项目时,我预计会出现异常

java spring-boot java-8 response option-type
5个回答
5
投票

Optional.of
期望纯粹的价值。您也可以在文档中找到信息,

/**
 * Constructs an instance with the described value.
 *
 * @param value the non-{@code null} value to describe
 * @throws NullPointerException if value is {@code null}
 */
private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

例如,

jshell> Optional.of(100)
$2 ==> Optional[100]

jshell> Optional.of(null)
|  Exception java.lang.NullPointerException
|        at Objects.requireNonNull (Objects.java:221)
|        at Optional.<init> (Optional.java:107)
|        at Optional.of (Optional.java:120)
|        at (#1:1)

如果您的值在运行时可能是

null
,您可以使用
.ofNullable
,

jshell> Optional.ofNullable(null)
$3 ==> Optional.empty

还有 函数式编程的思想是为所有输入返回一个值,而不是抛出破坏函数组合的

Exception

jshell> Function<Integer, Optional<Integer>> f = x -> Optional.of(x + 1)
f ==> $Lambda$23/0x0000000801171c40@6996db8

jshell> Function<Integer, Optional<Integer>> g = x -> Optional.of(x * 2)
g ==> $Lambda$24/0x0000000801172840@7fbe847c

jshell> f.apply(5).flatMap(x -> g.apply(x))
$13 ==> Optional[12]

因此,在您的示例中,您可以将

Optional.empty()
视为未找到的项目,但 Spring 也会将其视为
200
,这仍然比抛出
500
更好。
您可能希望发送
404
才能准确.

@GetMapping(
  value = "/compras", 
  produces = "application/json"
)
public Optional<Compras> retrieveAllCompras(@RequestParam String id) {
    return Optional.ofNullable(compraRepository.findById(id)); //will response as 200 even when no item found
}

您可以使用

ResponseEntity<A>
设置特定的 http 状态

传统的响应方式

404
定义特定的异常

import org.springframework.web.server.ResponseStatusException;
import org.springframework.http.HttpStatus;

@GetMapping(
  value = "/compras", 
  produces = "application/json"
)
public Compras retrieveAllCompras(@RequestParam String id) {
    return Optional.ofNullable(compraRepository.findById(id))
                   .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "item not found"))
}

1
投票

想想这里的类型,如果你想返回Optional,你会做一个

.orElse
,你必须再次包装它。这将是一种方法:

 @GetMapping(value = "/compras", produces = "application/json")
public Optional<Compras> retrieveAllCompras(@RequestParam String id) {
    return Optional.ofNullable(compraRepository.findById(id)).
                     map(Optional::of).
                     orElseThrow(() -> new RuntimeException("Not found"));

我来解释一下:

  1. Optional.ofNullable()
    将返回
    Optional<Compras>
    ,其值为
    Optional("some compras")
    或值
    Optional.Empty
  2. map(Optional::of)
    将再次包装可选,所以你将拥有
    Optional[Optional<Compras>]
    或(这里是技巧)Optional.Empty,因为map不包装Optional.Empty(这就是他在我们中间的原因)
  3. 最后,
    orElseThrow(() -> new RuntimeException("Not found"))
    将解压您的可选选项,在本例中从
    Optional[Optional<Compras>]
    Optional<Compras>
    ,或者,如果是
    Optional.Empty
    ,它将抛出异常

0
投票

您的控制器返回

Optional<Compras>
。这意味着不会调用
#get
方法。如果
Optional
值,您的控制器将返回 null。

更改为:

public Compras retrieveAllCompras...
,您将得到例外


0
投票

从对象名称和调用的方法(

compraRepository.findById(id)
)来看,您的服务实际上是一个存储库。如果它是 Spring Data 存储库,那么您应该将
Optional
的创建留给 Spring Data:存储库方法的 Null 处理。这样你就会拥有

compraRepository.findById(id).orElseThrow(NotFoundException::new)

0
投票

在我的例子中,我使用Optional类的isPresent()方法处理空响应:

@GetMapping("/{id}")
    public ResponseEntity<TraineeDto> getById(@PathVariable int id) {
        try {
            Optional<TraineeDto> traineeDto = traineeService.findById(id);
            if (traineeDto.isPresent()) {
                return ResponseEntity.ok(traineeDto.get());
            } else {
                return ResponseEntity.notFound().build(); // 404 Not Found
            }
        } catch (DataNotFoundException ex) {
            return ResponseEntity.notFound().build(); // 404 Not Found
        } catch (Exception ex) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); // 500 Internal Server Error
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.