如何在Java中获取嵌套的HashMap?

49

我有一个 Java 中的 HashMap,其内容(正如大家可能知道的那样)可以通过

HashMap.get("keyname");

如果我有一个嵌套的HashMap,也就是一个HashMap里面还包含另一个HashMap,我该如何访问其中的内容?我能够像这样内联方式进行访问吗:

HashMap.get("keyname").get("nestedkeyname");
谢谢您。

4
你可以考虑使用一个包含外部和内部键的关键对象,这样你只需要一个映射表,并且可能会有一个有用的新类型。 - Tom Hawtin - tackline
Objective-C有valueForKeyPath,Java也有类似的功能,请参考https://dev59.com/rEnSa4cB1Zd3GeqPSOpp。 - neoneye
11个回答

87

你可以像你所想的那样做。但是你的HashMap必须是有模板的:

Map<String, Map<String, String>> map = 
    new HashMap<String, Map<String, String>>();
否则,您需要在从第一个地图检索第二个地图后进行Map转换。
Map map = new HashMap();
((Map)map.get( "keyname" )).get( "nestedkeyname" );

在“=”后面,你不能只写new HashMap<>();吗?这样可以少打几个字...(可能是在1.8版本之前问的,那时候这么做是可行的)。 - JGFMK

26

您可以通过重复使用 .get() 方法来获取嵌套值,但是对于深度嵌套的映射,您需要进行大量的强制转换为 Map。更简单的方法是使用一个通用方法来获取嵌套值。

实现

public static <T> T getNestedValue(Map map, String... keys) {
    Object value = map;

    for (String key : keys) {
        value = ((Map) value).get(key);
    }

    return (T) value;
}

使用方法

// Map contents with string and even a list:
{
  "data": {
    "vehicles": {
      "list": [
        {
          "registration": {
            "owner": {
              "id": "3643619"
            }
          }
        }
      ]
    }
  }
}

List<Map> list = getNestedValue(mapContents, "data", "vehicles", "list");
Map first = list.get(0);
String id = getNestedValue(first, "registration", "owner", "id");

2
应该选择这个答案。 - iBug
这个回答是最具可扩展性和实用性的。 - eugene

14

是的。

可以参见:

public static void main(String args[]) {

    HashMap<String, HashMap<String, Object>> map = new HashMap<String, HashMap<String,Object>>();
    map.put("key", new HashMap<String, Object>());
    map.get("key").put("key2", "val2");

    System.out.println(map.get("key").get("key2"));
}

6
如果您计划构建具有可变深度的HashMap,请使用递归数据结构。以下是提供样例接口的实现:
class NestedMap<K, V> {

    private final HashMap<K, NestedMap> child;
    private V value;

    public NestedMap() {
        child = new HashMap<>();
        value = null;
    }

    public boolean hasChild(K k) {
        return this.child.containsKey(k);
    }

    public NestedMap<K, V> getChild(K k) {
        return this.child.get(k);
    }

    public void makeChild(K k) {
        this.child.put(k, new NestedMap());
    }

    public V getValue() {
        return value;
    }

    public void setValue(V v) {
        value = v;
    }
}

示例用法:

class NestedMapIllustration {
    public static void main(String[] args) {

        NestedMap<Character, String> m = new NestedMap<>();

        m.makeChild('f');
        m.getChild('f').makeChild('o');
        m.getChild('f').getChild('o').makeChild('o');
        m.getChild('f').getChild('o').getChild('o').setValue("bar");

        System.out.println(
            "nested element at 'f' -> 'o' -> 'o' is " +
            m.getChild('f').getChild('o').getChild('o').getValue());
    }
}

5
正如其他人所说,您可以这样做,但应该使用泛型定义地图,如下所示:
Map<String, Map<String, String>> map = new HashMap<String, Map<String,String>>();

然而,如果您只是盲目地运行以下命令:
map.get("keyname").get("nestedkeyname");

当keyname不在映射中时,您将收到空指针异常并且程序将崩溃。您应该添加以下检查:

String valueFromMap = null;
if(map.containsKey("keyname")){
  valueFromMap = map.get("keyname").get("nestedkeyname");
}

4

是的,如果你在外部哈希映射表中使用适当的泛型类型签名。

HashMap<String, HashMap<String, Foo>> hm = new HashMap<String, HashMap<String, Foobar>>();
// populate the map
hm.get("keyname").get("nestedkeyname");

如果您没有使用泛型,那么您需要进行转换才能从外部哈希映射中检索到的对象转换为HashMap(或至少是Map),然后才能调用其get()方法。但是您应该使用泛型 ;-)


3

我建议创建一个继承HashMap的自定义地图。然后只需覆盖get()方法,添加额外逻辑,以便如果地图不包含您的键,则会创建一个新的嵌套地图实例,将其添加到地图中,然后返回它。

public class KMap<K, V> extends HashMap<K, V> {

    public KMap() {
        super();
    }

    @Override
    public V get(Object key) {
        if (this.containsKey(key)) {
            return super.get(key);
        } else {
            Map<K, V> value = new KMap<K, V>();
            super.put((K)key, (V)value);
            return (V)value;
        }
    }
}

现在你可以这样使用:

Map<Integer, Map<Integer, Map<String, Object>>> nestedMap = new KMap<Integer, Map<Integer, Map<String, Object>>>();

Map<String, Object> map = (Map<String, Object>) nestedMap.get(1).get(2);
Object obj= new Object();
map.put(someKey, obj);

2
我来到这个StackOverflow页面是想寻找类似于objc中的valueForKeyPath的东西。我也看到了另一篇帖子 - Java的"Key-Value Coding",但最终我还是写了自己的代码。
我仍在寻找比apache的beanutils库中的PropertyUtils.getProperty更好的解决方案。

用法

Map<String, Object> json = ...
public String getOptionalFirstName() {
    return MyCode.getString(json, "contact", "firstName");
}

实现

public static String getString(Object object, String key0, String key1) {
    if (key0 == null) {
        return null;
    }
    if (key1 == null) {
        return null;
    }
    if (object instanceof Map == false) {
        return null;
    }
    @SuppressWarnings("unchecked")
    Map<Object, Object> map = (Map<Object, Object>)object;
    Object object1 = map.get(key0);
    if (object1 instanceof Map == false) {
        return null;
    }
    @SuppressWarnings("unchecked")
    Map<Object, Object> map1 = (Map<Object, Object>)object1;
    Object valueObject = map1.get(key1);
    if (valueObject instanceof String == false) {
        return null;
    }
    return (String)valueObject;
}

0

示例地图:

{
    "data": {
        "userData": {
            "location": {
                "city": "Banja Luka"
            }
        }
    }
}

实现:

public static Object getValueFromMap(final Map<String, Object> map, final String key) {
    try {
        final String[] tmpKeys = key.split("\\.");
        Map<String, Object> currentMap = map;
        for (int i = 0; i < tmpKeys.length - 1; i++) {
            currentMap = (Map<String, Object>) currentMap.get(tmpKeys[i]);
        }

        return currentMap.get(tmpKeys[tmpKeys.length - 1]);
    } catch (Exception exception) {
        return null;
    }
}

用法:

final Map<String, Object> data = new HashMap<>();
final Map<String, Object> userData = new HashMap<>();
final Map<String, Object> location = new HashMap<>();

location.put("city", "Banja Luka");
userData.put("location", location);
data.put("userData", userData);

System.out.println(getValueFromMap(data, "userData.location.city"));

结果:

Banja Luka

Process finished with exit code 0

0
import java.util.*;
public class MyFirstJava {
public static void main(String[] args)
{
  Animal dog = new Animal();
  dog.Info("Dog","Breezi","Lab","Chicken liver");
  dog.Getname();
  Animal dog2= new Animal();
  dog2.Info("Dog", "pumpkin", "POM", "Pedigree");
  dog2.Getname();
  HashMap<String,  HashMap<String, Object>> dogs = new HashMap<>();
  dogs.put("dog1", new HashMap<>() {{put("Name",dog.name); 
  put("Food",dog.food);put("Age",3);}});
  dogs.put("dog2", new HashMap<>() {{put("Name",dog2.name); 
  put("Food",dog2.food);put("Age",6);}});
  //dogs.get("dog1");
  System.out.print(dogs + "\n");
  System.out.print(dogs.get("dog1").get("Age"));

}


输出为:{dog2={年龄=6,名字=南瓜,食物=人类屁股},dog1={年龄=3,名字=Breezi,食物=鸡肝}}。 - user12193365

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