在 ifPresent 中收集 lambda

lambda collecting within a ifPresent

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

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

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

您可能想这样做:

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):将流限制为仅第一个元素(或者 returns 如果初始流为空,则为空流)

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

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

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

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

在我看来,哪个更易读,更清楚地表明了意图。

看起来你有一个包含零个或多个 InfoList<Info>,其中 Info 是某个具有 getMap() 方法的对象 return输入一个 Map<String, Something>,你想以一个 List<Something> 结束,这是第一个列表项的映射的所有值,它们具有键测试。

您想 map 可选而不是使用 ifPresentifPresent 是一个终端操作,它不 return 任何东西(只是执行代码)。

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>

假设 info.getMap returns a 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.

中值的类型