繁体   English   中英

转换地图<String,Object>到地图<String,String>

[英]Convert Map<String,Object> to Map<String,String>

如何将Map<String,Object>转换为Map<String,String>

这不起作用:

Map<String,Object> map = new HashMap<String,Object>(); //Object is containing String
Map<String,String> newMap =new HashMap<String,String>(map);

现在我们有了 Java 8/streams,我们可以在列表中再添加一个可能的答案:

假设每个值实际上都是String对象,则转换为String应该是安全的。 否则,可以使用一些其他机制将对象映射到字符串。

Map<String,Object> map = new HashMap<>();
Map<String,String> newMap = map.entrySet().stream()
     .collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue()));

如果您的Objects仅包含Strings ,那么您可以这样做:

Map<String,Object> map = new HashMap<String,Object>(); //Object is containing String
Map<String,String> newMap =new HashMap<String,String>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
       if(entry.getValue() instanceof String){
            newMap.put(entry.getKey(), (String) entry.getValue());
          }
 }

如果每个Objects都不是String那么您可以将(String) entry.getValue()替换为entry.getValue().toString()

泛型类型是编译时抽象。 在运行时,所有地图都将具有相同的类型Map<Object, Object> 因此,如果您确定值是字符串,则可以在 java 编译器上作弊:

Map<String, Object> m1 = new HashMap<String, Object>();
Map<String, String> m2 = (Map) m1;

将键和值从一个集合复制到另一个集合是多余的。 但是这种方法仍然不好,因为它违反了泛型类型安全。 可能您应该重新考虑您的代码以避免此类事情。

有两种方法可以做到这一点。 一种非常简单但不安全:

Map<String, Object> map = new HashMap<String, Object>();
Map<String, String> newMap = new HashMap<String, String>((Map)map);  // unchecked warning

另一种方式没有编译器警告并确保运行时的类型安全,更健壮。 (毕竟,你不能保证原始地图只包含 String 值,否则为什么它首先不是Map<String, String> ?)

Map<String, Object> map = new HashMap<String, Object>();
Map<String, String> newMap = new HashMap<String, String>();
@SuppressWarnings("unchecked") Map<String, Object> intermediate =
    (Map)Collections.checkedMap(newMap, String.class, String.class);
intermediate.putAll(map);

不可能。

这有点违反直觉。

你遇到了“苹果是水果”,但“每个水果都不是苹果”

去创建一个新地图并检查instance of with String

当您从 Object 转换为 String 时,我建议您捕获并报告(以某种方式,在这里我只是打印一条消息,这通常是不好的)异常。

    Map<String,Object> map = new HashMap<String,Object>(); //Object is containing String
    Map<String,String> newMap =new HashMap<String,String>();

    for (Map.Entry<String, Object> entry : map.entrySet()) {
        try{
            newMap.put(entry.getKey(), (String) entry.getValue());
        }
        catch(ClassCastException e){
            System.out.println("ERROR: "+entry.getKey()+" -> "+entry.getValue()+
                               " not added, as "+entry.getValue()+" is not a String");
        }
    }
private Map<String, String> convertAttributes(final Map<String, Object> attributes) {
    final Map<String, String> result = new HashMap<String, String>();
    for (final Map.Entry<String, Object> entry : attributes.entrySet()) {
        result.put(entry.getKey(), String.valueOf(entry.getValue()));
    }
    return result;
}

这里有很好的解决方案,还有一个考虑到处理null值的选项:

Map<String,Object> map = new HashMap<>();

Map<String,String> stringifiedMap = map.entrySet().stream()
             .filter(m -> m.getKey() != null && m.getValue() !=null)
             .collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue()));

虽然您可以通过强制转换和抑制警告来做到这一点

Map<String,Object> map = new HashMap<String,Object>();
// Two casts in a row.  Note no "new"!
@SuppressWarnings("unchecked")
Map<String,String> newMap = (HashMap<String,String>)(Map)map;  

这真的没有抓住重点。 :)

尝试将窄泛型类型转换为更宽泛的泛型类型意味着您首先使用了错误的类型。

打个比方:假设您有一个程序可以处理大量文本。 想象一下,您使用Objects (!!) 完成前半部分处理,然后决定使用正确类型作为String后半部分,因此您将范围从ObjectString 幸运的是,您可以使用 java(在这种情况下很容易)来做到这一点——但这只是掩盖了您在前半部分使用弱类型的事实。 不好的做法,没有争论。

这里没有区别(只是更难投射)。 您应该始终使用强类型。 至少使用一些基本类型 - 然后可以使用泛型通配符(“?扩展 BaseType”或“?超级 BaseType”)来提供类型兼容性和自动转换。 更好的是,使用正确的已知类型。 除非你有 100% 通用代码可以真正用于任何类型,否则永远不要使用 Object。

希望有帮助! :) :)


注意:通用强类型和类型转换仅存在于 .java 代码中。 编译为 .class 后,我们只剩下原始类型(Map 和 HashMap),没有泛型类型参数以及键和值的自动类型转换。 但它非常有帮助,因为 .java 代码本身是强类型且简洁的。

以下内容将转换您现有的条目。

TransformedMap.decorateTransform(params, keyTransformer, valueTransformer)

然而

MapUtils.transformedMap(java.util.Map map, keyTransformer, valueTransformer)

仅将新条目转换为您的地图

使用 Java 8 方式将Map<String, Object>Map<String, String> 此解决方案处理null值。

Map<String, String> keysValuesStrings = keysValues.entrySet().stream()
    .filter(entry -> entry.getValue() != null)
    .collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().toString()));

我发现使用番石榴最简单的方法:

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>30.1-jre</version>
    </dependency>

那么你可以这样做:

Map<String,Object> map = new HashMap<String,Object>(); 
Map<String,String> newMap = Maps.transformValues(map, Functions.toStringFunction());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM