Pau*_*ens 19 java functional-programming java-8 java-stream
是否有一种优雅的方式将其转换Map<P, Optional<Q>>为稀疏Map<P, Q>?
这应该工作,但它有点meh:
Map<P,Optional<Q>> map = ...;
Map<P,Q> map2 = map.entrySet()
.stream().filter(e -> e.getValue().isPresent())
.collect(Collectors.toMap(e -> e.getKey(), e->e.getValue().get()));
Run Code Online (Sandbox Code Playgroud)
Pol*_*ome 10
我会说你的方式几乎已经是最优雅的方式,我只做一些轻微的化妆品改变,并取代e -> e.getKey()你的收藏家Entry::getKey.这只是一个很小的改变,但比其他lambda更好地传达你的意图.
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()));
Run Code Online (Sandbox Code Playgroud)
为什么其他解决方案没有更好/更优雅?
因为它们不是更简洁,它们又陷入了不宣布你想要做什么的陷阱,而是如何在程序风格中常见,但在功能性风格中则不然.
如果你看一下上面的代码,它几乎是不言自明的,并且有很好的流程.首先使用带有Optionals 的非稀疏映射,然后在没有Optionals的情况下声明稀疏映射,然后描述将前映射转换为后者.这也没有副作用.仅在收集器实际完成时分配稀疏映射.
如果你看一下其他解决方案,那些会颠倒逻辑流程并使用程序化的思维方式:
Map<P, Optional<Q>> map = [....];
Map<P, Q> sparseMap = new HashMap<>();
map.forEach((key, opt) -> opt.ifPresent(value -> sparseMap.put(key, value)));
Run Code Online (Sandbox Code Playgroud)
这只是稍微短一点:
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))
Run Code Online (Sandbox Code Playgroud)
由于类型推断,您可以节省一些字符,但最后,如果您合理地格式化它们,两个foreach解决方案都需要4个LOC,因此它们不会短于功能性.他们也不清楚.在相反,他们依靠导致的副作用在其他地图.这意味着在计算过程中,您将获得分配给变量的部分构造的稀疏映射.使用功能解决方案,只有在正确构造地图时才会分配地图.这只是一个小小的挑剔,并且在这种情况下可能不会引起问题,但是对于可能变得相关的其他情况(例如,当涉及并发时)时要记住,特别是当其他地图不是局部变量,但是一个字段 - 或者更糟糕的是,从其他地方传入.
此外,功能方法可以更好地扩展 - 如果您拥有大量数据,则切换到并行流是非常简单的,将foreach-approach 转换为并行需要重写功能filter/ collect方法.这与这种轻量级操作无关(事实上,这里不做,可能更慢),但在其他情况下可能是一个理想的特性.
在我看来,使用功能filter/ collect方法比使用程序更可取foreach,因为你训练自己使用好习惯.但请记住,"优雅"往往是旁观者的眼睛.对我来说,更"优雅"的方式是没有副作用的正确功能方式.因人而异.
这个怎么样:
Map<P, Q> map2 = new HashMap<>();
map.forEach((key, opt) -> opt.ifPresent(value -> map2.put(key, value)));
Run Code Online (Sandbox Code Playgroud)
当您创建新地图并通过迭代原始地图来添加值时,它会更简单:
Map<P, Q> map2 = new HashMap<>();
map.forEach((p, q) -> map2.compute(p, (k, v) -> q.orElse(null)));
Run Code Online (Sandbox Code Playgroud)
value.isPresent()将返回所有将返回的原始条目false(不包括在内result):Map.compute在remappingFunction产生时删除/忽略键的映射null.
这是一个澄清如何处理空值的示例:
Map<String, Optional<Integer>> map = new HashMap<>();
map.put("one", Optional.of(1));
map.put("two", Optional.of(2));
map.put("three", Optional.empty());
map.put("four", Optional.of(4));
map.put("five", Optional.empty());
Map<String, Integer> map2 = new HashMap<>();
map.forEach((p, q) -> map2.compute(p, (k, v) -> q.orElse(null)));
System.out.println(map2);
Run Code Online (Sandbox Code Playgroud)
输出是{four=4, one=1, two=2}(当map2.compute得到null从q.orElse,p不被添加到map2)
| 归档时间: |
|
| 查看次数: |
935 次 |
| 最近记录: |