web-dev-qa-db-fra.com

Comment accéder aux HashMaps imbriqués en Java?

J'ai un HashMap en Java, dont le contenu (comme vous le savez probablement tous) est accessible par

HashMap.get("keyname");

Si un HashMap se trouve dans un autre HashMap, c'est-à-dire un HashMap imbriqué, comment puis-je accéder au contenu? Puis-je faire ça comme ça, en ligne:

HashMap.get("keyname").get("nestedkeyname");

Je vous remercie.

29

Vous pouvez le faire comme vous l'avez supposé. Mais votre HashMap doit être modelé:

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

Sinon, vous devez effectuer un transtypage en Map après avoir récupéré la deuxième carte à partir de la première.

Map map = new HashMap();
((Map)map.get( "keyname" )).get( "nestedkeyname" );
62
tangens

Oui.

Voir:

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"));
}
8
Benjamin Borden

Si vous prévoyez de construire des HashMaps avec une profondeur variable , utilisez une structure de données récursive.

Voici une implémentation fournissant un exemple d'interface:

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

et exemple d'utilisation:

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
Matt

Comme d'autres l'ont dit, vous pouvez le faire, mais vous devez définir la carte avec des génériques comme ceci:

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

Cependant, si vous exécutez simplement aveuglément ce qui suit:

map.get("keyname").get("nestedkeyname");

vous obtiendrez une exception de pointeur nul chaque fois que le nom de clé n'est pas dans la carte et que votre programme se bloquera. Vous devez vraiment ajouter la vérification suivante:

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

Oui, si vous utilisez la signature de type générique appropriée pour la table de hachage externe.

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

Si vous n'utilisez pas de génériques, vous devez effectuer une conversion pour convertir l'objet récupéré de la carte de hachage externe en HashMap (ou au moins un Map) avant de pouvoir appeler sa méthode get(). Mais vous devriez utiliser des génériques ;-)

4
David Z

Je préfère créer une carte personnalisée qui étend HashMap. Remplacez simplement get () pour ajouter une logique supplémentaire afin que si la carte ne contient pas votre clé. Il créera une nouvelle instance de la carte imbriquée, l'ajoutera, puis la renverra.

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

Vous pouvez maintenant l'utiliser comme ceci:

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);
3
Cody Wagner

Je suis venu sur cette page StackOverflow à la recherche d'un quelque chose d'ala valueForKeyPath connu de objc. Je suis également venu par un autre post - "Key-Value Coding" pour Java , mais j'ai fini par écrire le mien.

Je cherche toujours une meilleure solution que PropertyUtils.getProperty dans la bibliothèque beanutils d'Apache.

Usage

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

La mise en oeuvre

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