Java HashMap - 是否有必要对每个集合使用 .put()?

2022-09-03 13:52:54

想象一下以下场景。您有一组已经可访问和已知的值。出于某种原因,您必须将它们放入HashMap中。

代码示例:

String a = "a";
Strinb b = "b";
...
HashMap map = new HashMap(5);
map.put("a", a);
map.put("b", b);
...

真的有必要这样做吗?我不敢相信没有一个构造函数可以让你从头开始输入你的值。

我说的是这样的东西:

HashMap map = new HashMap(<"a", a>, <"b", b>, ...);

甚至像这样:

HashMap map = new HashMap(5);
HashMap.putBunchOfStuff("a", a, "b", b, ...);

编辑:我的目的是问是否有方法,但更重要的是如果答案是“否”,为什么没有这样的构造函数/方法。


答案 1

不幸的是,集合文字是Java 7(和Java 8)中Project Coin的提议但它从未进入最终产品,也就是说它不是Java的一个功能。

命题是这样的

Here’s how it would look with map literals:


    final Map<Integer, String> platonicSolids = { 
          4 : "tetrahedron",
          6 : "cube", 
          8 : "octahedron", 
          12 : "dodecahedron", 
          20 : "icosahedron"
    };


Here is the empty map literal, which has a slightly irregular syntax to make
it differ from the empty set:


    Map<String, Integer> noJokeHere = { : };

但它从未发生过,所以不幸的是,这不起作用。因此,除非你像Per-Åke Minborg的这个网站一样编写自己的魔法建造者或花哨的lambda,否则你只能靠自己。但是,站点中的以下内容应该可以正常工作(在Java 8中)。

//copy paste from linked site
Map<Integer, String> map = Stream.of(
            new SimpleEntry<>(0, "zero"),
            new SimpleEntry<>(1, "one"),
            //...
            new SimpleEntry<>(11, "eleven"),
            new SimpleEntry<>(12, "twelve"))
            .collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()));

还有简化版,也来自网站

//copy paste from linked site
public static <K, V> Map.Entry<K, V> entry(K key, V value) {
    return new AbstractMap.SimpleEntry<>(key, value);
}

public static <K, U> Collector<Map.Entry<K, U>, ?, Map<K, U>> entriesToMap() {
    return Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue());
}

Map<Integer, String> map = Stream.of(
            entry(0, "zero"),
            //...
            entry(12, "twelve"))
            .collect(entriesToMap());

由于以下几点,未引入集合文本:

  • 此功能的“简单”版本(仅集,列表,地图)不是很令人满意或受欢迎;此功能的“可扩展”版本是开放式的,凌乱的,并且几乎可以保证超出其设计预算;

  • 基于库的版本以1%的成本为我们提供了X%的收益,其中X>>1;

  • 价值类型即将到来,在具有价值类型的世界中,“此功能会是什么样子”可能与在没有价值类型的世界中完全不同,这表明在价值类型之前尝试做这项工作是值得怀疑的;

  • 我们最好将语言设计带宽的重点放在解决基于库的版本背后的更多基本问题上(包括:更有效的varargs,常量池中的数组常量,不可变数组以及对缓存(和在压力下回收)中间不可变结果的支持)。

作者:Brian Goetz,来自甲骨文


答案 2

默认情况下没有这样的构造函数 - 您可以在实例化时使用双括号习语来表示映射中的所有值,但这仍然需要多个 put 调用:put

Map<String,String> map = new HashMap<>() {{
    put("a", "val1");
    put("b", "val2");
    //etc.
}};

实际上,您通常要将大量数据块放入可从流或其他集合访问的映射中,因此在此实例中循环多个调用是微不足道的。put

番石榴在其上有一个,使您能够在实例化之前做类似的事情。其他外部库可能有其他类似的行为,但事实是你必须求助于使用外部库。putAll()ImmutableMap.Builder