lambda收集在ifPresent中

时间:2017-07-26 06:01:14

标签: java lambda java-8 java-stream collectors

如何使用collect方法在嵌套的ifPresent方法中进行收集?

到目前为止,这就是我所拥有的:

List result = list.stream()
                  .findFirst()
                  .ifPresent(info -> {
                      info.getMap()
                          .stream()
                          .filter( entry -> entry.getKey().equals("test"))
                          .map(entry::getValue)
                          .collect(Collectors.toList())                          
                   });

3 个答案:

答案 0 :(得分:4)

你可能想这样做:

List result = list.stream()
    .limit(1)
    .flatMap(info -> // <-- removed brace {
        info.getMap().stream()
            .filter( entry -> entry.getKey().equals("test"))
            .map(entry::getValue)
    ) // <-- removed brace here too
    .collect(Collectors.toList());

让我解释一下:

.limit(1):仅将流限制为第一个元素(如果初始流为空,则返回空流)

.flatMap():将流映射到新流。在这种情况下,将返回由Entry#getValue()的值组成的新流

.collect(Collectors.toList()):最后将值流收集到列表中。

正如OlivierGrégoire在评论中所说,以下内容也有效:

List result = list.stream()
    .limit(1)
    .flatMap(info -> info.getMap().stream())
    .filter( entry -> entry.getKey().equals("test"))
    .map(entry::getValue)
    .collect(Collectors.toList());

在我看来,更可读和更清楚地表明意图是什么。

答案 1 :(得分:3)

假设info.getMap返回java.util.Map,我根本不知道为什么你需要内部流管道。

只需使用get("test")获取"test"密钥的值:

List result = 
    list.stream()
        .map(info -> info.getMap().get("test"))
        .filter(Objects::nonNull)
        .limit(1)
        .collect(Collectors.toList()); 

P.S。,不要使用原始类型。您应该将返回列表的类型更改为List<ValueType>,其中ValueTypeinfo.getMap() Map中值的类型。

答案 2 :(得分:1)

看起来您的List<Info>包含零个或多个Info个,其中Info是某个对象,其getMap()方法返回Map<String, Something>并且你想得到List<Something>,这是第一个列表项的地图的所有值都有关键测试。

您希望map是可选的,而不是使用ifPresentifPresent是一个终端操作,它不返回任何内容(只执行代码)。

list // List<Info>
    .stream() // Stream<Info>
    .findFirst() // Optional<Info>
    .map(info -> info.getMap().entrySet() // Set<Entry<String, Something>>
         .stream() // Stream<Entry<String, Something>>
         .filter(entry -> entry.getKey().equals("test"))
         .map(Entry::getValue) // Stream<Something>
         .collect(toList()) // List<Something>
    ) // Optional<List<Something>>
    .orElse(Collections::emptyList) // List<Something>

如果未指定最后一行,那么您将获得Optional<List<Info>>返回。

编辑:Lino对limit的回答更加惯用,除非你真的想以这种方式使用Optional,否则选择那个。

编辑2:

假设您的上述代码是您完整的业务逻辑,您可能只是在列表的第一项中找到“test”的值(感谢Lino为limit)。那就是:

list.stream() // Stream<List<Info>>
    .limit(1) // Stream<List<Info>> count 0/1
    .flatMap(info::getMap) Stream<Map<String, Something>> 0/1
    .map(map -> map.get("test")) Stream<Something> 0/1, possibly null
    .filter(Objects::nonNull) Stream<Something> 0/1
    .findFirst() Optional<Something>

为了完整起见,如果您想在列表中的地图中找到“test”的任何值,那么它将是:

list.stream() // Stream<List<Info>>
    .flatMap(info::getMap) Stream<Map<String, Something>> 
    .flatMap(map -> map.entrySet().stream()) // Stream<Entry<String, Something>>
    .filter(entry -> entry.getKey().equals("test"))
    .map(Entry::getValue) // Stream<Something>
    .collect(toList()) // List<Something>