这可能是一种不好的做法,但我无法为我的问题找到更好的解决方案。所以我有这张地图
// Map<state, Map<transition, Map<property, value>>>
private Map<String, Map<String, Map<String, String>>> properties;
我想初始化它,所以我没有NullPointerException
这个
properties.get("a").get("b").get("c");
我试过这个,但我没有工作(显然)
properties = new HashMap<String, Map<String, Map<String,String>>>();
我试过的其他事情没有编译。
此外,如果您有任何想法如何避免这种嵌套地图,我将不胜感激。
答案 0 :(得分: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
}
如果您实施自己的密钥类,您的地图将如下所示:
Map<Key, String> map = new HashMap<Key, String>();
在地图中查找某些内容时,您可以使用:
map.get(new Key("a", "b", "c"));
上面的方法不会抛出NullPointerException。
请记住,要使此解决方案正常工作,您需要在Key类中重写equals和hashcode。有帮助here。如果不重写equals和hashcode,则具有相同元素的新键将与映射中的现有键不匹配。
还有其他可能的解决方案,但在我看来,实现自己的密钥非常干净。如果您不想使用构造函数,可以使用静态方法初始化密钥,并使用以下内容:
Key.build(a, b, c)
由你决定。
答案 1 :(得分: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>());
如果您的目标是没有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>();
}
};
}
};
}
答案 2 :(得分: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;
}
可以这样调用:
String result = get(properties, "a", "b", "c");
请注意,使用它时需要小心,因为它不是类型安全的。
答案 3 :(得分:1)
使用此结构执行此操作的唯一方法是使用所有可能的键预初始化第1级和第2级映射。如果无法做到这一点,则无法通过普通地图实现您的要求。
作为替代方案,您可以构建更宽容的自定义数据结构。例如,一个常见的技巧是失败的键查找返回“空”结构而不是null,允许嵌套访问。
答案 4 :(得分:1)
你无法一次性初始化它,因为你通常不知道你将提前拥有什么键。
因此,您必须检查键的子图是否为空,如果是,则可能为其添加空映射。最好只在向条目添加条目时执行该操作,并且在检索条目时,如果路径中的某个子图不存在,则返回null。您可以将它包装在您自己的地图实现中,以方便使用。
作为替代方案,apache commons集合'MultiKeyMap可能会提供您想要的内容。
答案 5 :(得分:1)
使用properties.get("a").get("b").get("c");
是不可能的,除非您制作自己的地图,否则请务必避免null
。实际上,您无法预测您的地图将包含“b”键。
因此,请尝试创建自己的类来处理嵌套的get
。
答案 6 :(得分:1)
我认为更好的解决方案是使用对象作为值映射的唯一键。密钥将由三个字段state
,transition
和property
组成。
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Key {
private String state;
private String transition;
private String property;
public Key(String state, String transition, String property) {
this.state = state;
this.transition = transition;
this.property = property;
}
@Override
public boolean equals(Object other) {
return EqualsBuilder.reflectionEquals(this, other);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
当您检查值时,地图将返回null
以获取与值无关的键
Map<Key, String> values = new HashMap<Key, String>();
assert values.get(new Key("a", "b", "c")) == null;
values.put(new Key("a", "b", "c"), "value");
assert values.get(new Key("a", "b", "c")) != null;
assert values.get(new Key("a", "b", "c")).equals("value");
要有效且正确地将对象用作Map
中的键,您应该覆盖方法equals()
和hashCode()
。我使用Commons Lang库的反射功能构建了thos方法。
答案 7 :(得分:0)
我认为,以下是更简单的方法:
public static final Map<Integer, Map<Integer, Map<Integer, Double>>> A_Map = new HashMap<Integer, Map<Integer, Map<Integer, Double>>>()
{
{
put(0, new HashMap<Integer, Map<Integer, Double>>()
{
{
put(0, new HashMap<Integer, Double>()
{
{
put(0, 1 / 60.0);
put(1, 1 / 3600.0);
}
});
put(1, new HashMap<Integer, Double>()
{
{
put(0, 1 / 160.0);
put(1, 1 / 13600.0);
}
});
}
});
put(1, new HashMap<Integer, Map<Integer, Double>>()
{
{
put(0, new HashMap<Integer, Double>()
{
{
put(0, 1 / 260.0);
put(1, 1 / 3600.0);
}
});
put(1, new HashMap<Integer, Double>()
{
{
put(0, 1 / 560.0);
put(1, 1 / 1300.0);
}
});
}
});
}
};