Java 8的Optional<List>返回True,为什么?

huangapple go评论78阅读模式
英文:

Java 8 Optional <List> returning True Why?

问题

我有一个REST控制器

@GetMapping("/getByClientId/{clientId}")
public ResponseEntity<Optional<List<EquityFeeds>>> getByClientId(@PathVariable("clientId") final String clientId) {

    Optional<List<EquityFeeds>> cId = Optional.ofNullable(equityFeedsService.findByClientId(clientId));

    System.out.println("Client Id: " + cId);

    if (cId.isPresent()) {
        return ResponseEntity.ok(cId);
    } else {
        cId.orElseThrow(() -> new ClientIdNotFoundException(clientId));
    }
    return ResponseEntity.ok(cId);
}

Service类代码:

public List<EquityFeeds> findByClientId(String clientId) {

    List<EquityFeeds> cId = equityFeedsRedisRepositoryImpl.findByClientId(clientId);
    System.out.println("In EquityFeedService " + cId);
    return cId;
}

Impl.代码(REDIS):

public List<EquityFeeds> findByClientId(String clientId) {
    return (List<EquityFeeds>) listOperations.range(clientId, 0, -1);
}

问题:
1)当使用REST控制器调用getClientId,并且clientId不存在于REDIS缓存中时:

Service类代码返回:In EquityFeedService []

REST控制器返回:Client Id: Optional[[]]

在REST控制器中,代码进入if循环并且在屏幕上不显示任何内容,因为列表是空的,即:

if (cId.isPresent()) {
    return ResponseEntity.ok(cId);
}
为什么?为什么cId.isPresent()返回true,并且代码进入if循环。理论上,代码应该进入else循环并抛出异常,因为列表是空的。这似乎只在列表的情况下发生,因为我的另一个返回POJO类型的方法没有这个问题。

请帮我理解这种行为,以及应该采取什么措施来解决这个问题。
英文:

I have a REST Controller

@GetMapping(&quot;/getByClientId/{clientId}&quot;)
 public ResponseEntity&lt;Optional&lt;List&lt;EquityFeeds&gt;&gt;&gt; getByClientId(@PathVariable(&quot;clientId&quot;) final String clientId) {

 Optional&lt;List&lt;EquityFeeds&gt;&gt; cId = Optional.ofNullable(equityFeedsService.findByClientId(clientId));

  System.out.println(&quot;Client Id: &quot;+cId);

        if(cId.isPresent()) {
           return ResponseEntity.ok(cId);
        } else {
           cId.orElseThrow(() -&gt; new ClientIdNotFoundException(clientId));
        }
        return ResponseEntity.ok(cId);
     }

Service Class Code:

public List&lt;EquityFeeds&gt; findByClientId(String clientId) {

        List&lt;EquityFeeds&gt; cId = equityFeedsRedisRepositoryImpl.findByClientId(clientId);
        System.out.println(&quot;In EquityFeedService &quot;+cId);
        return cId;
    }

Impl. Code (REDIS):

public List&lt;EquityFeeds&gt; findByClientId(String clientId) {
      return (List&lt;EquityFeeds&gt;) listOperations.range(clientId, 0, -1);
}

Issue:

  1. When the getClientId is called using a REST Controller and the clientId is not present in the REDIS Cache then:

    Service class Code returns: In EquityFeedService []

    The REST Controller returns: Client Id: Optional[[]]

In the REST Controller the code goes inside the if loop and displays nothing on the screen since the List is empty i.e.

if(cId.isPresent()) {
           return ResponseEntity.ok(cId);
 }

Why? Why cId.isPresent() returns true and the code goes inside the if loop. Ideally the code should go inside the else loop and throw an Exception since the List is empty. This is happening in case of List only it seems as my other method which has a return type of POJO doesn't have this issue.

Please help me understand this behavior and what should be done to fix this.

答案1

得分: 3

cId.isPresent()返回true,因为List&lt;EquityFeeds&gt;不为null,它是一个空列表。

如果!cId.get().isEmpty()为真,则返回ResponseEntity.ok(cId);,否则抛出ClientIdNotFoundException(clientId);异常。

英文:

cId.isPresent() return true because
List&lt;EquityFeeds&gt; is not null , it's empty list

if(!cId.get().isEmpty()) {
   return ResponseEntity.ok(cId);
} else {
   throw new ClientIdNotFoundException(clientId);
}

答案2

得分: 0

Optional.isPresent返回true的原因是存在一个实际值 - 一个空的ListOptional会检查它所持有的值是否为null,没有其他内容。isPresent检查的是值是否存在于Optional内部,而不是存在于List内部。

因此,您必须稍微不同地处理Optional。此外,不要将Optional用作替代if-else结构的方式。

以下是一种方法:

return cId.filter(Predicate.not(List::isEmpty))         // 如果列表不为空
          .map(ResponseEntity::ok)                      // 创建响应
          .orElseThrow(() ->                            // 否则抛出异常
               new ClientIdNotFoundException(clientId)); 

顺便说一下,您不希望将包裹在ResponseEntity中的Optional返回。解包它并返回List本身。如果它是空的或null已经处理过了,异常会首先被抛出。

return cId.filter(Predicate.not(List::isEmpty))         
          .map(Optional::get)                          // 从Optional中提取
          .map(ResponseEntity::ok)
          .orElseThrow(() -> new ClientIdNotFoundException(clientId));
英文:

The reason the Optional.isPresent returns true is that there is an actual value - an empty List. The Optional checks whether the value it holds is a null or not, nothing else. The isPresent checks whether the value is present inside the Optional, not inside the List itself.

So you have to treat Optional a bit different. Moreover, don't use Optional like that as substitution to the if-else constructs.

Here is a way to go:

return cId.filter(Predicate.not(List::Empty))            // if the list is not empty
          .map(ResponseEntity::ok)                       // create a response
          .orElseThrow(() -&gt;                             // or else throw an exception
               new ClientIdNotFoundException(clientId)); 

By the way, you don't want to return Optional wrapped inside the ResponseEntity. Unwrap it and return the List itself. If it is empty or null was already handled and the exception would be thrown first.

return cId.filter(Predicate.not(List::Empty))            
          .map(Optional::get)                            // exctract from the Optional
          .map(ResponseEntity::ok)
          .orElseThrow(() -&gt; new ClientIdNotFoundException(clientId)); 

huangapple
  • 本文由 发表于 2020年4月11日 01:10:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/61145200.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定