如何将Map 转换为Map ? (选项:使用番石榴)

我有一个Map String键只是数字值,如“123”等。我正在获取数值,因为这些值来自我的JSF组件中的UI。 我不想更改UI组件的合同。

现在我想基于上面的Map创建一个Map ,我在Maps类中看到了一些transform方法,但都关注转换值而不是键。

有没有更好的方法将Map转换为Map

更新Java 8

您可以使用流来执行此操作:

 Map newMap = oldMap.entrySet().stream() .collect(Collectors.toMap(e -> Long.parseLong(e.getKey()), Map.Entry::getValue)); 

这假设所有键都是Long s的有效字符串表示。 此外,您可以在转换时发生碰撞; 例如, "0""00"都映射到0L


我认为你必须迭代地图:

 Map newMap = new HashMap(); for(Map.Entry entry : map.entrySet()) { newMap.put(Long.parseLong(entry.getKey()), entry.getValue()); } 

此代码假定您已清理了map所有值(因此没有无效的长值)。

我希望有更好的解决方案。

编辑

我在Commons Collection-Utils中遇到了CollectionUtils#transformedCollection(Collection, Transformer)方法,看起来它可能会做你想要的。 从头开始,它只适用于实现Collection类。

@Vivin的答案是正确的,但我认为解释为什么Guava没有任何方法允许你转换Map的键(或根本不转换Set )是有用的。

所有Guava用于转换和过滤的方法都会产生惰性结果……函数/谓词仅在需要时应用,因为使用了对象。 他们不创建副本。 因此,转换很容易打破Set的要求。

比方说,例如,你有一个Map ,它包含“1”和“01”作为键。 它们都是不同的String ,因此Map可以合法地包含两个键。 但是,如果使用Long.valueOf(String)转换它们,它们都映射到值1 。 它们不再是不同的钥匙。 如果您创建地图副本并添加条目,则不会破坏任何内容,因为任何重复的密钥都将覆盖该密钥的上一个条目。 然而,一个经过时间间隔改造的Map无法强制执行唯一键,因此会破坏Map的合约。

您现在可以使用Java 8流,map,collect以更易读,更干净的方式执行此操作。

 Map oldMap Map newMap = oldMap.entrySet().stream() .collect(Collectors.toMap(entry -> Long.parseLong(entry.getKey()), Map.Entry::getValue)); 

下面是其中一个答案的更新版本,使得生成的Map不可修改(不,它不使用Guava,只是简单的Java 8):

  import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toMap; ... newMap = oldMap.entrySet().stream().collect(collectingAndThen( toMap((Map.Entry entry) -> transformKey(entry.getKey()), (Map.Entry entry) -> transformValue(entry.getValue())), Collections::unmodifiableMap))); 

简短的回答是否定的,Guava没有开箱即用。

简单的方法就像下面这样。 但是,有一些警告。

  public static  Map transformMap(Map map, Function keyFunction, Function valueFunction) { Map transformedMap = newHashMap(); for (Entry entry : map.entrySet()) { transformedMap.put( keyFunction.apply(entry.getKey()), valueFunction.apply(entry.getValue())); } return transformedMap; } public static  Map transformKeys(Map map, Function keyFunction) { return transformMap(map, keyFunction, Functions.identity()); } 

番石榴的变形金刚都是“懒惰的”或基于视图的。 我认为要实现一个地图密钥转换器,你需要一个双向function。 我的理解是,Guava团队正在开发一个转换器,可以解决这个问题。

你遇到的另一个问题是你必须处理重复的可能性才能成为另一种番石榴原则的“ 吉米certificate ”。 处理它的一种方法是返回Multimap ; 另一种方法是在遇到重复时抛出exception。 我不建议隐藏问题,例如忽略带有重复键的后续条目,或者用重复键覆盖新条目。