Как определить содержимое карты при инициализации?

Мне просто было интересно, можно ли определить содержимое объекта карты при инициализации.

Например, можно создать массив как:

new String[] {“apples”, “bananas”, “pears”}

Итак, мне было интересно, можем ли мы сделать что-то подобное для карт.


person Larry    schedule 30.01.2011    source источник
comment
Тесно связанный: stackoverflow.com/questions/507602/   -  person Jonik    schedule 18.07.2013


Ответы (4)


Вы можете как бы использовать этот синтаксический трюк:

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

Хотя не очень приятно. Это создает анонимный подкласс HashMap и заполняет его в инициализаторе экземпляра.

person skaffman    schedule 30.01.2011
comment
Хороший трюк. Я бы поместил эти внутренние {} в отдельные строки, так как сейчас это выглядит очень запутанным. - person Sergei Tachenov; 30.01.2011
comment
@Sergey: Конечно, какой стиль ты предпочитаешь. Однако я всегда использовал этот стиль, и всякий раз, когда я вижу этот трюк, он также использует этот стиль. К этому привыкаешь. Главное - это инициализатор, на него и нужно ориентироваться. - person skaffman; 30.01.2011
comment
Что ж, я впервые вижу этот трюк, думаю, это объясняет путаницу. - person Sergei Tachenov; 30.01.2011
comment
Это действительно плохая практика: она приводит к утечке ссылки на текущий объект. Я хотел бы проголосовать против, но пока не могу. - person Andrea Ratto; 15.04.2015
comment
Спасибо за предупреждение @AndreaRatto - тем, кто хочет получить дополнительную информацию о том, почему: это потому, что новый объект map содержит неявный объект this, ссылающийся на родительский объект. Подробнее здесь: blog.jooq.org/2014/12/08/ - person Dan Alvizu; 09.05.2017
comment
Строительное решение лучше, но @AndreaRatto, я ненавижу себя за то, что даже предлагаю это, но не могли бы вы сразу создать нормальную HashMap из текущей версии, чтобы устранить утечку? new HashMap<String,String>(new HashMap<String,String>() {{put("x", "y"); put("a", "b");}}); - person Ryan; 04.10.2017

Если ваш Map будет неизменным после создания, и вы не против добавления зависимости, Guava предлагает неплохой беглый синтаксис:

Map<K,V> aMap = ImmutableMap.<K,V>builder().put(key0, val0).put(key1,val1).build();

Если вы чувствуете себя действительно экзотично, Scala имеет синтаксис, точно такой же, как вы хотите, и совместим с другими Java. код:

val aMap = Map("a"->0, "b"->1)

Обратите внимание, что компилятор Scala определит общий тип Map от String до Int в зависимости от того, что вы в него вставили, хотя вы также можете указать его явно.

Однако, если это всего лишь разовое задание, я бы выбрал синтаксис на основе инициализатора. И у библиотеки Guava, и у языка Scala есть еще много чего порекомендовать, но изучение совершенно новой библиотеки / языка может оказаться за бортом.

person Carl    schedule 30.01.2011
comment
+1 за ссылку на Scala :-) - person Landei; 30.01.2011

Вы можете использовать блоки инициализатора:

class Foo {
   //using static initializer block 
   static Map<String,String> m1 = new HashMap<String,String>();
   static {
      m1.put("x","y");
      m1.put("a","b");
   }    

   //using initializer block 
   Map<String,String> m2 = new HashMap<String,String>();
   {
      m2.put("x","y");
      m2.put("a","b");
   }    

} 
person Landei    schedule 30.01.2011
comment
Кто-то однажды указал мне, что использование инициализаторов экземпляров вместо конструкторов - плохая идея, особенно потому, что это затрудняет обработку исключений. статические инициализаторы, тем не менее, подходят. - person Sergei Tachenov; 30.01.2011
comment
@Sergey: Зависит. Прочтите это: stackoverflow.com/questions/1355810/ - person Peter Knego; 30.01.2011
comment
Я бы не стал помещать в инициализаторы код, подверженный ошибкам, но для безопасных операций, таких как заполнение коллекций, я не вижу проблем. - person Landei; 30.01.2011

Что-то очень хитрое ... можно улучшить, но это всего лишь направление: Определите статический помощник для преобразования массива объектов в карту этого типа:

    public static<K,V> Map<K, V> fromArray(Object[] anObjArray){
    int size = anObjArray.length;
    Map<K, V> aMap = new HashMap<K, V>();
    for (int i=0;i<=size/2;i=i+2){
        K key = (K)anObjArray[i];
        V value = (V)anObjArray[i+1];
        aMap.put(key, value);
    }
    return aMap;
}

то вы можете создать карту, используя это:

        Map<Integer, String> aMap = MapUtils.<Integer, String>fromArray(new Object[]{1, "one", 2,"two"});

Я бы лично поддержал предложение строителя Gauva от @Carl :-)

person Biju Kunjummen    schedule 30.01.2011