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

Posted

技术标签:

【中文标题】将 Map<String,Object> 转换为 Map<String,String>【英文标题】:Convert Map<String,Object> to Map<String,String> 【发布时间】:2013-05-24 07:13:33 【问题描述】:

如何将Map&lt;String,Object&gt; 转换为Map&lt;String,String&gt;

这不起作用:

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

【问题讨论】:

你想做什么? 你传递的对象是字符串吗? 在这种情况下你期望/希望发生什么:` Map map = new Map() map.put("key", new Integer(42 ));` 迭代迭代中的map1(map)将Object转换为字符串并使用oldString和新转换的String创建newMap 由于不是每个Object 都是String,因此您可以对Map 的每个值调用toString()。但这就是你所说的“转换”吗? 【参考方案1】:

现在我们有了 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()));

【讨论】:

需要格外小心: Map newMap = map.entrySet().stream() .filter(entry -> entry.getValue() instanceof String) .collect(Collectors.toMap (Map.Entry::getKey, e -> (String)e.getValue())); 为什么不e.getValue().toString()为什么要显式转换? @AntonBalaniuc 我们假设 OP 知道这些值都是字符串,所以在这里我们使用更严格的强制转换而不是从对象中强制字符串值.当然,正如答案中提到的,如果有一些其他机制更适合从值 Objects 创建字符串,则应使用该机制而不是强制转换。 @AntonBalaniuc 老问题,但打电话给toString() 可能很危险......让我解释一下。如果出于某种原因,您要转换为 String 的对象实际上不是您期望概括为对象的 String,而是其他东西,toString() 方法可能会为您提供该对象的标记化值,从而引入难以检测的错误你的代码。在这种情况下,铸造至少会抛出RuntimeException【参考方案2】:

如果您的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()

【讨论】:

更好的String.valueOf来防止NullPointerException【参考方案3】:

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

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

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

【讨论】:

【参考方案4】:

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

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

另一种方式没有编译器警告并确保运行时的类型安全,更健壮。 (毕竟不能保证原来的map只包含String值,不然怎么一开始就不是Map&lt;String, String&gt;呢?)

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);

【讨论】:

【参考方案5】:

不可能。

这有点违反直觉。

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

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

【讨论】:

【参考方案6】:

当您从 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");
        
    

【讨论】:

【参考方案7】:

使用 Java 8 方式将 Map&lt;String, Object&gt; 转换为 Map&lt;String, String&gt;。此解决方案处理 null 值。

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

【讨论】:

【参考方案8】:

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

TransformedMap.decorateTransform(params, keyTransformer, valueTransformer)

在哪里

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

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

【讨论】:

Apache Common Collections 中的TransformedMap 和 MapUtils commons.apache.org/proper/commons-collections【参考方案9】:
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;

【讨论】:

虽然添加代码确实可以解决问题,但最好为代码添加一些解释,以便未来的访问者和语言新手可以更好地理解和学习它。欢迎使用 Stack Overflow!【参考方案10】:

这里有很好的解决方案,只是考虑处理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()));

【讨论】:

【参考方案11】:

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

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 进行后半部分,因此您从Object 缩小到String。幸运的是,你可以用 java 来做到这一点(在这种情况下很容易)——但这只是掩盖了你在前半部分使用弱类型的事实。不好的做法,没有争论。

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

希望对您有所帮助! :) :)


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

【讨论】:

【参考方案12】:

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

    <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());

【讨论】:

以上是关于将 Map<String,Object> 转换为 Map<String,String>的主要内容,如果未能解决你的问题,请参考以下文章

如何将map<string list<>>转换成城map<string,object>

Java 将 Map<String,Set<String>> 转换为 Map<String,Set<Object1>> [关闭]

将Map<String,Object>格式转换成Map<String ,String[]>格式

将 JSON 映射到 List<Map<<String, Object>>

如何将两个List<Map<String,Object>>合并为一个

list<String>如何转化为Map<String, Object>,list<EmpVO>如何转化为Map<String, Object>