关于Java HashMap:Java HashMap – 是否有必要为每个集合使用.put()?

Java HashMap - Is it necessary to use .put() for each set?

本问题已经有最佳答案,请猛点这里访问。

想象一下下面的场景。您有一组已经可以访问和已知的值。因为某些原因,你必须把它们放在哈希图中。

代码示例:

1
2
3
4
5
6
7
String a ="a";
Strinb b ="b";
...
HashMap map = new HashMap(5);
map.put("a", a);
map.put("b", b);
...

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

我说的是这样的事情:

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

或者类似的事情:

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

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


不幸的是,集合文字是JAVA 7(和Java 8)中的Project Boin的一个提议,但它从来没有把它变成最终的产品,也不是Java的一个特性。

提议是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 = { : };

但它从未发生过,所以不幸的是,这不起作用。所以除非你在这个网站上写下你自己的魔术师或者神奇的lambda?克明博格,你自己一个人。不过,下面的站点应该工作(在Java 8中)。

1
2
3
4
5
6
7
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()));

以及简化版,也来自网站:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//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>>1;

  • 值类型即将出现,"此功能将是什么样子的"在一个有值类型的世界中,可能与在一个世界中完全不同如果没有,建议尝试做这项工作是有问题的。值类型之前;

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

作者:Oracle的Brian Goetz


可以使用varargs创建一个非常实用的方法来创建地图。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> newMap(Object... elems) {
    HashMap<K, V> m = new HashMap<K, V>();

    for (int i = 0; i < elems.length; i += 2) {
        m.put((K) elems[i], (V) elems[i + 1]);    
    }

    return m;
}

Map<String, Integer> m = newMap("k1", 1,"k2", 2);

注意:这不是类型安全的,如果在使用时出错,可能会导致带有错误类型的对象的映射,从而将ClassCastException扔到意外的地方。这叫做堆污染。例子:

1
2
Map<String, Integer> m = newMap("k1", 1,"k2","2");
int s = m.get("k2");  // ClassCastException!


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

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

实际上,您通常需要将大量的数据放入一个可以从流或另一个集合访问的映射中,因此在这种情况下,循环多次put调用是很简单的。

guava的ImmutableMap.Builder上有一个putAll(),使您能够在实例化之前做类似的事情。其他外部库也可能有其他类似的行为,但事实上,您将不得不求助于使用外部库。


您可以使用类似的方法:

1
2
3
4
HashMap<String, String> map = new HashMap<String, String>(5){{
    put("a","a");
    put("b","b");
}};

但我不知道你是否可以用局部变量a和b。