在一个语句中一次向 HashMap 添加多个条目

Posted

技术标签:

【中文标题】在一个语句中一次向 HashMap 添加多个条目【英文标题】:adding multiple entries to a HashMap at once in one statement 【发布时间】:2012-01-05 20:38:10 【问题描述】:

我需要初始化一个常量 HashMap,并希望在一行语句中完成。避免这样的事情:

  hashMap.put("One", new Integer(1)); // adding value into HashMap
  hashMap.put("Two", new Integer(2));      
  hashMap.put("Three", new Integer(3));

与目标 C 中的类似:

[NSDictionary dictionaryWithObjectsAndKeys:
@"w",[NSNumber numberWithInt:1],
@"K",[NSNumber numberWithInt:2],
@"e",[NSNumber numberWithInt:4],
@"z",[NSNumber numberWithInt:5],
@"l",[NSNumber numberWithInt:6],
nil] 

看了这么多,我还没有找到任何例子来说明如何做到这一点。

【问题讨论】:

【参考方案1】:

您可以使用双大括号初始化,如下所示:

Map<String, Integer> hashMap = new HashMap<String, Integer>()

     put("One", 1);
     put("Two", 2);
     put("Three", 3);
;

作为一条警告,请参阅线程 Efficiency of Java “Double Brace Initialization" 了解它可能对性能产生的影响。

【讨论】:

@user387184 是的,他们称之为“双括号初始化器”。看到这个话题:***.com/questions/924285/… 你不应该使用这种方法。它会在您每次使用它时创建一个新类,它的性能比简单地创建一个地图要差很多。见***.com/questions/924285/… 我对此投反对票的原因是因为它没有解释每次使用它都会创建一个新类。我认为人们应该意识到这样做的权衡。 @TimoTürschmann 似乎如果我需要对这样的地图进行静态初始化,它也是静态的,消除了每次使用它的性能损失 - 你d有那个惩罚一次。我看不到其他任何时候人们会希望这种初始化没有变量是静态的(例如,有人会在循环中使用它吗?)。不过我可能错了,程序员很有创造力。 请不要使用这种反模式,它是actively dangerous 并且有合理的替代方案。【参考方案2】:

您可以使用 Google Guava 的 ImmutableMap。只要您不关心以后修改 Map 就可以使用此方法(使用此方法构建地图后无法在地图上调用 .put() ):

import com.google.common.collect.ImmutableMap;

// For up to five entries, use .of()
Map<String, Integer> littleMap = ImmutableMap.of(
    "One", Integer.valueOf(1),
    "Two", Integer.valueOf(2),
    "Three", Integer.valueOf(3)
);

// For more than five entries, use .builder()
Map<String, Integer> bigMap = ImmutableMap.<String, Integer>builder()
    .put("One", Integer.valueOf(1))
    .put("Two", Integer.valueOf(2))
    .put("Three", Integer.valueOf(3))
    .put("Four", Integer.valueOf(4))
    .put("Five", Integer.valueOf(5))
    .put("Six", Integer.valueOf(6))
    .build();

另请参阅:http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html

一个有点相关的问题:ImmutableMap.of() workaround for HashMap in Maps?

【讨论】:

Guava 很大,除非绝对必要,否则我不会将它用于我的 android 应用程序 注意ImmutableMap 不接受null 键或值。 @ericn ProGuard 允许您排除您不使用的库的任何部分。【参考方案3】:

从 Java 9 开始,可以使用Map.of(...),如下所示:

Map<String, Integer> immutableMap = Map.of("One", 1, 
                                           "Two", 2, 
                                           "Three", 3);

这张地图是不可变的。如果您希望地图是可变的,则必须添加:

Map<String, Integer> hashMap = new HashMap<>(immutableMap);

如果您不能使用 Java 9,您只能自己编写类似的帮助方法或使用第三方库(如 Guava)为您添加该功能。

【讨论】:

添加10个条目后,它抛出奇怪的错误“无法解析方法”,这是这个方法的错误吗? @vikramvi 是的 如果你看documentation Map.of 最多只能完成 10 个条目,因为它非常费力【参考方案4】:

Maps 在 Java 9 中还添加了工厂方法。对于最多 10 个条目,Maps 具有采用键和值对的重载构造函数。例如,我们可以构建一个不同城市及其人口的地图(根据 2016 年 10 月的 google)如下:

Map<String, Integer> cities = Map.of("Brussels", 1_139000, "Cardiff", 341_000);

Map 的 var-args 情况有点困难,你需要同时拥有键和值,但在 Java 中,方法不能有两个 var-args 参数。因此,一般情况是通过采用 Map.Entry&lt;K, V&gt; 对象的 var-args 方法并添加构造它们的静态 entry() 方法来处理的。例如:

Map<String, Integer> cities = Map.ofEntries(
    entry("Brussels", 1139000), 
    entry("Cardiff", 341000)
);

Collection Factory Methods in Java 9

【讨论】:

如果您可以使用 Java 9+,那就太好了。这些工厂方法也返回不可变映射。【参考方案5】:

Java 没有映射文字,因此没有很好的方法可以完全按照您的要求进行操作。

如果您需要这种类型的语法,请考虑一些 Groovy,它与 Java 兼容并且可以让您这样做:

def map = [name:"Gromit", likes:"cheese", id:1234]

【讨论】:

【参考方案6】:

这是一个简单的类,可以完成你想要的

import java.util.HashMap;

public class QuickHash extends HashMap<String,String> 
    public QuickHash(String...KeyValuePairs) 
        super(KeyValuePairs.length/2);
        for(int i=0;i<KeyValuePairs.length;i+=2)
            put(KeyValuePairs[i], KeyValuePairs[i+1]);
    

然后使用它

Map<String, String> Foo=QuickHash(
    "a", "1",
    "b", "2"
);

这会产生a:1, b:2

【讨论】:

【参考方案7】:
    boolean x;
    for (x = false, 
        map.put("One", new Integer(1)), 
        map.put("Two", new Integer(2)),      
        map.put("Three", new Integer(3)); x;);

忽略x 的声明(这是避免“无法访问的声明”诊断所必需的),从技术上讲,它只是一个声明。

【讨论】:

这太恶心了。 @MicahStairs - 但这只是一个声明。 没错,但这是我绝不希望在生产中偶然发现的那种代码。 @MicahStairs - 我见过更糟糕的情况。 天哪,我今天搜索了这个,这个代码是如何工作的?我已将它添加到代码中进行测试,但我无法弄清楚它是如何在内部工作的...... :)【参考方案8】:

您可以将此实用程序函数添加到实用程序类中:

public static <K, V> Map<K, V> mapOf(Object... keyValues) 
    Map<K, V> map = new HashMap<>();

    for (int index = 0; index < keyValues.length / 2; index++) 
        map.put((K)keyValues[index * 2], (V)keyValues[index * 2 + 1]);
    

    return map;


Map<Integer, String> map1 = YourClass.mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = YourClass.mapOf("key1", "value1", "key2", "value2");

注意:在Java 9 中你可以使用Map.of

【讨论】:

不应使用此方法,因为该实现不是类型安全的!示例: Map map1 = mapOf(1, "value1", "key", 2, 2L); 好吧,我希望定义 Map&lt;Integer, String&gt; 的程序员也提供这些类型...【参考方案9】:

基于@Dakusan(定义扩展HashMap的类)提出的解决方案,我这样做了:

  public static HashMap<String,String> SetHash(String...pairs) 
     HashMap<String,String> rtn = new HashMap<String,String>(pairs.length/2);
     for ( int n=0; n < pairs.length; n+=2 ) rtn.put(pairs[n], pairs[n + 1]);
    return rtn; 
  

.. 并以这种方式使用它:

HashMap<String,String> hm = SetHash( "one","aa", "two","bb", "tree","cc");

(不确定这种方式是否有任何缺点(我不是 java 开发人员,只需要在 java 中完成一些任务),但它可以工作并且在我看来很舒服。)

【讨论】:

【参考方案10】:

另一种方法可能是编写特殊函数,通过正则表达式从一个字符串中提取所有元素值:

import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Example 
    public static void main (String[] args)
        HashMap<String,Integer> hashMapStringInteger = createHashMapStringIntegerInOneStat("'one' => '1', 'two' => '2' , 'three'=>'3'  ");

        System.out.println(hashMapStringInteger); // one=1, two=2, three=3
    

    private static HashMap<String, Integer> createHashMapStringIntegerInOneStat(String str) 
        HashMap<String, Integer> returnVar = new HashMap<String, Integer>();

        String currentStr = str;
        Pattern pattern1 = Pattern.compile("^\\s*'([^']*)'\\s*=\\s*>\\s*'([^']*)'\\s*,?\\s*(.*)$");

        // Parse all elements in the given string.
        boolean thereIsMore = true;
        while (thereIsMore)
            Matcher matcher = pattern1.matcher(currentStr);
            if (matcher.find()) 
                returnVar.put(matcher.group(1),Integer.valueOf(matcher.group(2)));
                currentStr = matcher.group(3);
            
            else
                thereIsMore = false;
            
        

        // Validate that all elements in the given string were parsed properly
        if (currentStr.length() > 0)
            System.out.println("WARNING: Problematic string format. given String: " + str);
        

        return returnVar;
    

【讨论】:

以上是关于在一个语句中一次向 HashMap 添加多个条目的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 GCP 在 pubsub 模型中一次向所有订阅者发送消息

我们可以一次向钱包添加多个通行证吗?

如何在 Django 中一次将多个对象添加到 ManyToMany 关系?

如何在 UITableView 中一次添加多个单元格的边框?

jmeter中一次查询多条sql语句

一次向多个设备推送通知