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

84

如何将 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);

你想要做什么? - lc2817
你传递的对象是一个字符串吗? - Shreyos Adikari
你在这种情况下期望/希望发生什么: Map<String, Object> map = new Map<String, Object>() map.put("key", new Integer(42)); - Shreyos Adikari
在迭代map1(映射)时,将Object转换为字符串并创建一个新的Map,其中包含旧字符串和新转换的字符串。 - Sanath
由于并非每个“Object”都是“String”,因此您可以在“Map”的每个值上调用“toString()”。但这就是您所说的“转换”吗? - user1907906
12个回答

75

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

2
通过一些额外的注意: Map<String,String> newMap = map.entrySet().stream() .filter(entry -> entry.getValue() instanceof String) .collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue())); - Balázs Németh
2
为什么不使用 e.getValue().toString(),而要使用显式转换? - Anton Balaniuc
1
@AntonBalaniuc 我们假设OP知道值都是字符串,所以这里我们使用了更严格的强制转换而不是从对象中强制转换字符串值。当然,如答案中提到的,如果有其他更适合从值对象创建字符串的机制,应该使用该机制而不是转换。 - skeryl
2
@AntonBalaniuc 这是一个老问题,但调用 toString() 可能会很危险... 让我解释一下。如果由于任何原因你想要转换为字符串的对象实际上不是你期望的字符串,而是其他类型的对象,toString() 方法可能会给你该对象的标记化值,从而在代码中引入难以检测的错误。在这种情况下,强制转换至少会抛出 RuntimeException - Przemysław Gęsieniec

35

如果你的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) entry.getValue()”替换为“entry.getValue().toString()”。

3
使用更好的 String.valueOf 来避免空指针异常。 - Patrick Parker

28

通用类型是一种编译时的抽象概念,在运行时所有的映射都会有相同的类型Map<Object, Object>。因此,如果你确定值是字符串,你可以欺骗Java编译器:


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

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


这应该被接受为答案!这绝对是最快的选择。 - mrek

7

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

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

另一种方法没有编译警告,并在运行时确保类型安全,这更为健壮。毕竟,您无法保证原始映射仅包含字符串值,否则为什么一开始不是 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);

4

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

3

由于您将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");
        }
    }

3

不可能。

这有点违反直觉。

你遇到了“苹果是水果”但“每个水果都不是苹果”的情况。

创建一个新的映射并使用instance of with String进行检查。


2
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;
}

2
在添加代码的同时,加入一些解释会更好,这样未来的访问者和新手可以更好地理解和学习。欢迎来到 Stack Overflow! - DeadChex

2

这里提供了很好的解决方案,还有一种考虑到处理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()));

2
以下内容将转换您现有的条目。
TransformedMap.decorateTransform(params, keyTransformer, valueTransformer)

相反,

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

只将新条目转换到您的地图中


1
Apache Common Collections 中的 TransformedMap 和 MapUtils http://commons.apache.org/proper/commons-collections/ - arulraj.net

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接