如何正确地懒惰初始化地图的地图?

use*_*882 5 java collections map

这可能是一种不好的做法,但我无法为我的问题找到更好的解决方案.所以我有这张地图

// Map<state, Map<transition, Map<property, value>>>
private Map<String, Map<String, Map<String, String>>> properties;
Run Code Online (Sandbox Code Playgroud)

我想初始化它,所以我不喜欢NullPointerException这个

properties.get("a").get("b").get("c");
Run Code Online (Sandbox Code Playgroud)

我尝试了这个,但我没有工作(显然)

properties = new HashMap<String, Map<String, Map<String,String>>>();
Run Code Online (Sandbox Code Playgroud)

我试过的其他东西没编译.

此外,如果您有任何想法如何避免这种嵌套地图,我将不胜感激.

Rav*_*lau 9

在我看来,你需要创建自己的Key类:

public class Key {
   private final String a;
   private final String b;
   private final String c;
   public Key(String a, String b, String c) {
      // initialize all fields here
   }

   // you need to implement equals and hashcode. Eclipse and IntelliJ can do that for you
}
Run Code Online (Sandbox Code Playgroud)

如果您实现自己的密钥类,您的地图将如下所示:

Map<Key, String> map = new HashMap<Key, String>();
Run Code Online (Sandbox Code Playgroud)

在地图中寻找某些东西时,您可以使用:

map.get(new Key("a", "b", "c"));
Run Code Online (Sandbox Code Playgroud)

上面的方法不会抛出NullPointerException.

请记住,要使此解决方案起作用,您需要在Key类中重写equals和hashcode.有帮助这里.如果不重写equals和hashcode,则具有相同元素的新键将与映射中的现有键不匹配.

还有其他可能的解决方案,但在我看来,实现自己的密钥非常干净.如果您不想使用构造函数,可以使用静态方法初始化密钥,并使用以下内容:

Key.build(a, b, c)
Run Code Online (Sandbox Code Playgroud)

它是由你决定.


Ser*_*nev 5

您需要在地图中的地图中放置地图.从字面上看:

properties = new HashMap<String, Map<String, Map<String,String>>>();
properties.put("a", new HashMap<String, Map<String,String>>());
properites.get("a").put("b", new HashMap<String,String>());
Run Code Online (Sandbox Code Playgroud)

如果您的目标是延迟初始化而无需NPE创建自己的地图:

private static abstract class MyMap<K, V> extends HashMap<K, V> {
    @Override
    public V get(Object key) {
        V val = super.get(key);
        if (val == null && key instanceof K) {
            put((K)key, val = create());
        }
        return val;
    }

    protected abstract V create();
}


public void initialize() {
    properties = new MyMap<String, Map<String, Map<String, String>>>() {
        @Override
        protected Map<String, Map<String, String>> create() {
            return new MyMap<String, Map<String, String>>() {
                @Override
                protected Map<String, String> create() {
                    return new HashMap<String, String>();
                }
            };
        }
    };

}
Run Code Online (Sandbox Code Playgroud)


McD*_*ell 5

您可以使用实用程序方法:

  public static <T> T get(Map<?, ?> properties, Object... keys) {
    Map<?, ?> nestedMap = properties;
    for (int i = 0; i < keys.length; i++) {
      if (i == keys.length - 1) {
        @SuppressWarnings("unchecked")
        T value = (T) nestedMap.get(keys[i]);
        return value;
      } else {
        nestedMap = (Map<?, ?>) nestedMap.get(keys[i]);
        if(nestedMap == null) {
          return null;
        }
      }
    }
    return null;
  }
Run Code Online (Sandbox Code Playgroud)

这可以像这样调用:

String result = get(properties, "a", "b", "c");
Run Code Online (Sandbox Code Playgroud)

请注意,使用它时需要小心,因为它不是类型安全的.