如何使用双括号初始化Map of Map

5

我知道双括号初始化有其隐藏的成本,但是否有可能初始化 Map<String,Map<String,String>>() 的其他方法?

我的尝试:

Map<String, Map<String, String>> defaultSourceCode = new HashMap<String, Map<String, String>>(){
            {"a",new HashMap<String, String>(){{"c","d"}}}
        };

我知道这是一种不好的实践,但为了尝试而已。

参考和动机:Arrays.asList也适用于映射吗?


这是合法的Java语法吗? - user11044402
是的:https://dev59.com/ZlkS5IYBdhLWcg3wCShx - Vishwa Ratna
@LutzHorn,完成了! - Vishwa Ratna
5
建议尽可能避免使用这种数据结构,而更倾向于使用具体的类。 - Naman
2
@CommonMan https://dev59.com/4XI-5IYBdhLWcg3wO1rl#1958961 和 https://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/ - rkosegi
显示剩余5条评论
2个回答

9

您可以使用Java9中提供的Map.of()方法,它返回一个不可变的映射:

Map<String, Map<String, String>> map = Map.of("a", Map.of("c", "d"));

或者使用 Map.ofEntries:
Map<String, Map<String, String>> map1 = Map.ofEntries(
        Map.entry("a", Map.of("c", "d"))
);

2
喜欢它并点赞,但我正在寻找双括号初始化。不过像往常一样,谢谢 :) - Vishwa Ratna
1
@CommonMan 是的,ofEntries 可以解决这个问题。 - Ruslan
2
在很多情况下,20个参数的列表已经足够让人混淆哪些是键,哪些是值了。这个限制有一个很好的理由。ofEntries可以接受几乎无限数量的项目,并且可以清楚地表明哪些是键,哪些是值。 - Ole V.V.
1
@OleV.V. 好的限制原因是您无法声明支持不同键和值类型的varargs方法,因此只能声明具有显式参数列表的重载方法。这可能与您的想法相一致,即太多的参数会令人困惑,但主要原因纯粹是技术上的。 - Holger
1
@Holger 在一个自制的库中,我看到了一个接受Object...并返回map的方法。你可以传递奇数数量的参数并得到异常,或者传递完全错误的类型。如果有强烈的意愿,技术上的限制是可以克服的(不用说我的意愿并不强烈)。 - Ole V.V.
显示剩余5条评论

5
几乎所有的东西都没问题,你只需要在双括号中使用方法调用即可:
Map<String, Map<String, String>> defaultSourceCode = new HashMap<String, Map<String, String>>(){
    {put("a",new HashMap<String, String>(){{put("c","d");}});}
};

但是这个答案解释了为什么你不应该这样做。


有趣的是,Eclipse要求我为这些类定义一个“serialVersionUID”。 - user11044402
1
这是一个非常著名的反模式!请不要这样做。 - Eugene
@Eugene,你说得非常正确,我附加了更多信息。 - Andronicus
2
@LutzHorn 嗯,这是与这种反模式相关的问题的重要提示。这会创建一个可序列化类的子类,并且序列化这样的映射将创建对此匿名类的持久引用。当然,添加 serialVersionUID 也无法解决问题(除了你无论如何都做不到)。例如,周围类中的小改变,比如再次为不同的映射使用这种反模式,可能会导致类文件的重新编号,从而使持久映射无效。更不用说意外引用外部对象和任何捕获的变量了... - Holger

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