如何使用Java Stream检查集合是否不为空

8
我是新手Java 8开发者,不太理解以下代码的问题所在。这段代码的目的是当Collection<User>不为空时发送它,但如果集合为空,则发送HttpStatus.NOT_FOUND实体响应。
@RequestMapping(value = "/find/pks", 
                method = RequestMethod.GET, 
                produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Collection<User>> getUsers(@RequestBody final Collection<String> pks)
{
    return StreamSupport.stream(userRepository.findAll(pks).spliterator(), false)
         .map(list -> new ResponseEntity<>(list , HttpStatus.OK))
         .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}

在以下代码中,Eclipse显示了错误:.orElse

对于类型Stream<ResponseEntity<User>>,方法orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND))未定义。

我的基本接口方法如下所示:

Iterable<T> findAll(Iterable<PK> pks);

3
Stream.map()方法返回一个Stream对象,而Stream对象没有orElse()方法。如果你返回一个Iterable对象,会让自己的生活变得更加复杂。为什么不返回List或Set甚至是Collection,并使用isEmpty()方法呢?另外,你正在映射的不是一个列表,而是一个用户。如果你确实想继续使用Iterable,可以使用iterable.iterator().hasNext()来检查它是否为空。 - JB Nizet
该接口由Spring包之一提供。 - Saurabh Kumar
2
然后使用 iterable.iterator().hasNext() 来查看它是否为空。但是话说回来,在这种情况下我不会返回 404。而是简单地返回一个带有空列表的 200。404 是用于获取未知资源的情况。你在这里搜索资源,找不到任何内容也是一种有效的结果。 - JB Nizet
3个回答

7

你把两件事混淆了。第一个任务是将Iterable转换为Collection,这可以使用Stream API解决:

Collection<User> list=
    StreamSupport.stream(userRepository.findAll(pks).spliterator(), false)
   .collect(Collectors.toList());

请注意,此流是 用户 User ,而不是列表流。因此,您无法使用此流将 list 映射到其他内容。 map 操作将把流的每个元素映射到新元素。
然后,您可以使用此列表创建 ResponseEntity
return list.isEmpty()? new ResponseEntity<>(HttpStatus.NOT_FOUND):
                       new ResponseEntity<>(list, HttpStatus.OK);

您可以通过创建一个执行这些步骤的Collector来将这些步骤组合在一起,尽管这并没有提供任何优势,但只是个人风格上的问题。
ResponseEntity<User> responseEntity=
    StreamSupport.stream(userRepository.findAll(pks).spliterator(), false)
   .collect(Collectors.collectingAndThen(Collectors.toList(),
      list -> list.isEmpty()? new ResponseEntity<>(HttpStatus.NOT_FOUND):
                              new ResponseEntity<>(list, HttpStatus.OK) ));

1
非常感谢你的回答,Holger。我修改了你的代码并加入了map函数,将每个User转换为UserDTO。'StreamSupport.stream(userRepository.findAll(pks).spliterator(), false).map(UserDTO::new).collect( Collectors.collectingAndThen(Collectors.toList(), list -> list.isEmpty() ? new ResponseEntity<>(HttpStatus.NOT_FOUND) : new ResponseEntity<>(list, HttpStatus.OK)));' - Saurabh Kumar
Collectors.collectingAndThen() 是一个很好的静态方法。 - Saifur

5

把所有内容都挤在一行里不是必要的,而且经常会犯错误。在这种情况下,你不能这样做 - 没有适合你意图的API。

保持简单:

Collection<User> list = <your stream code that gets a list>;
if (list.isEmpty())
    return new ResponseEntity<>(HttpStatus.NOT_FOUND);
return new ResponseEntity<>(list, HttpStatus.OK);

但是如果你非常必须:

return <your code>.map(list -> new ResponseEntity<>(list, list.isEmpty() ? HttpStatus.NOT_FOUND : HttpStatus.OK));

他正在询问一个一般问题的简化版本。如果在生成流的集合上应用了过滤器,那么它是否为空就不明显了。 - user1743310

1

这取决于您对流的终端操作,记住流只能被消费一次。

  • 如果是分组/统计操作,则会得到一个计数为0或组映射为空的情况。
  • 如果收集到列表中,则是空列表。
  • 如果是返回Optional的方法(例如findAny)之一,则可以使用Optional的空值检查方法。

但是他正在寻找的概念不是流和直通,而是在实际传递时执行一些副逻辑?因此不会破坏流或消费一次的概念... - user1743310

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接