我会说你的方式几乎已经是最优雅的方式,我只会做一些轻微的外观改变,并用.这只是一个很小的变化,但比其他lambda更好地传达了你的意图。e -> e.getKey()
Entry::getKey
Map<P, Optional<Q>> map = new HashMap<>();
Map<P, Q> sparseMap = map.entrySet().stream()
.filter(e -> e.getValue().isPresent())
.collect(Collectors.toMap(Entry::getKey, e -> e.getValue().get()));
为什么其他解决方案不是更好/更优雅?
因为它们不是更简洁,而且它们再次陷入了不声明你想要做什么,而是如何做的陷阱,这在程序风格中很常见,但在功能风格中却不那么常见。
如果你看一下上面的代码,它几乎是不言自明的,并且有很好的流程。首先有一个带有 s 的非稀疏映射,然后声明不带 s 的稀疏映射,然后描述前者映射到后者的转换。这也没有副作用。仅当收集器实际完成时,才会分配稀疏映射。Optional
Optional
如果你看看其他解决方案,那些颠倒逻辑流并使用程序式思维方式:
Map<P, Optional<Q>> map = [....];
Map<P, Q> sparseMap = new HashMap<>();
map.forEach((key, opt) -> opt.ifPresent(value -> sparseMap.put(key, value)));
这只比略短:
Map<P, Optional<Q>> map = [....];
Map<P, Q> sparseMap = new HashMap<>();
for (Entry<P, Optional<Q>> e : map.entrySet()) e.getValue().ifPresent(value -> sparseMap.put(key, value))
由于类型推断,您可以节省一些字符,但最终,如果您合理地格式化它们,则两种解决方案都需要4个LOC,因此它们不会比功能解决方案短。它们也不是更清楚。相反,它们依赖于在另一张地图中引起副作用。这意味着在计算过程中,您将获得分配给变量的部分构造的稀疏映射。使用功能解决方案,仅当正确构造映射时才会分配映射。这只是一个小的挑剔,在这种情况下可能不会引起问题,但对于其他可能变得相关的情况(例如,当涉及并发时),特别是当另一个映射不是局部变量而是字段时 - 或者更糟的是,从其他地方传入。foreach
此外,函数方法的扩展性更好 - 如果您有大量数据,切换到并行流是微不足道的,将-方法转换为并行无论如何都需要重写为功能/方法。这与这种轻量级操作无关(实际上,不要在这里这样做,它可能会更慢),但在其他情况下,这可能是一个理想的特征。foreach
filter
collect
在我看来,使用函数式/方法比使用程序式更好,因为您训练自己使用良好的习惯。但请记住,“优雅”往往在旁观者的眼中。对我来说,更“优雅”的方式是没有副作用的适当功能方式。新浪网.filter
collect
foreach