问题 Java HashMap - 是否有必要为每个集合使用.put()? [重复]


这个问题在这里已有答案:


3108
2018-05-06 14:00


起源

Idk,如果Java8有一些新的诡计。但 这个 几年前问过这个问题,而且共识是否定的。另见 这个 - chancea
你不能这样做...但你可以使用putAll(Map(K,v))添加另一个Map; - Gnanadurai A
我想知道它是否从一开始就可以访问,为什么不使用它 enums,或者如果你不喜欢重复键和值,那么为什么不呢 Set,或者您可以创建定义的“MyHashMap” put(Object o) - CsBalazsHungary
@CsBalazsHungary在实际问题上有点复杂。这只是伪代码。 - OddDev
@OddDev您应该始终提供尽可能接近实际代码的代码。否则你可能正在解决错误的问题。 - Kayaman


答案:


不幸, 集合文字 是一个 项目硬币的提案 在Java 7(和Java 8)中,但是 它从未成为最终产品,也就是说它不是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 = { : };

但它从未发生过,所以不幸的是,这不起作用。所以,除非你写自己的魔法建设者或花哨的lambda 在这个Per-ÅkeMinborg的网站上,你是独自一人。但是,该站点的以下内容应该可以使用(在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,数组常量) 常量池,不可变数组,以及对缓存(和回收)的支持 在压力下)中间不可变结果)。

来自Oracle的Brian Goetz


14
2018-05-06 14:20



......你的意思是第二个,对吧?第一个是命题。从未发生过。 - EpicPandaForce
不,我一般都在谈论答案。非常好,清晰的信息和我正在寻找的信息。我不打算抓住代码片段。 - OddDev
啊,在这种情况下,我很高兴你发现它有用,欢迎你! :) - EpicPandaForce


默认情况下没有这样的构造函数 - 你可以使用双括号成语 put 实例化时地图中的所有值,但这仍然需要多次put调用:

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

实际上,您通常需要将大块数据放入可从流或其他集合访问的地图中,因此循环使用多个数据非常简单 put 在这种情况下调用。

番石榴有一个 putAll() 在它的 ImmutableMap.Builder,使您能够在实例化之前执行类似的操作。其他外部库可能有其他类似的行为,但事实是你不得不求助于使用外部库。


1
2018-05-06 14:06



注意:双括号初始化会创建一个匿名子类,如果它在非静态上下文中使用,它会保留对外部实例的强引用(从而使其保持活动状态)。 - Radiodef
@Radiodef这是真的 - 我觉得它根本不是一个理想的习惯用语(它更像是一种模糊语法的意外而不是为此用途设计的东西。) - Michael Berry


可以使用varargs创建一个漂亮的实用工具方法来创建地图。

例:

@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 在意想不到的地方这就是所谓的 堆污染。例:

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

1
2018-05-06 14:13





你可以使用这样的东西:

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

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


0
2018-05-06 14:09



注意:这会创建一个匿名子类,如果它在非静态上下文中使用,它会保留对外部实例的强引用(从而使其保持活动状态)。 - Radiodef