Есть ли лучшая практика для написания карт буквального стиля в Java? - PullRequest
27 голосов
/ 26 сентября 2010

Короче говоря, если вы хотите написать карту, например. константы в Java, которые, например, Python и Javascript вы бы написали как литерал,

T<String,String> CONSTANTS =
{
    "CONSTANT_NAME_0": CONSTANT_VALUE_0 ,
    "CONSTANT_NAME_1": CONSTANT_VALUE_1 ,
    "CONSTANT_NAME_2": CONSTANT_VALUE_2 ,
    //...
} ;

есть ли Class или какая-либо предустановка Object, которую вы можете использовать для написания такой структуры данных?

Ответы [ 9 ]

50 голосов
/ 04 марта 2011

Мне нравится делать это так:

Map map = new HashMap() {{
    put("foo", "bar");
    put(123, 456);
}};

Двойной {{}} является блоком инициализации экземпляра. Они немного необычны, но они полезны. Нет необходимости в библиотеках или помощниках.

35 голосов
/ 26 сентября 2010

Нет, у Java нет литерала карты. Самое близкое, к чему вы придете, - это использование Google Collections ' ImmutableMap :

Map<K,V> CONSTANTS = ImmutableMap.of(
    NAME_1, VALUE_1,
    NAME_2, VALUE_2
    //etc.
  );
15 голосов
/ 26 сентября 2010

Константы ?Я бы использовал enum .

public enum Constants { 
    NAME_1("Value1"),
    NAME_2("Value2"),
    NAME_3("Value3");

    private String value;

    Constants(String value) {
        this.value = value;
    }

    public String value() {
        return value;
    }
}

Значение, например, NAME_2 можно получить следующим образом:

String name2value = Constants.NAME_2.value();

Только перечисление будет немного большеразумное имя, например Settings, Defaults и т. д., независимо от того, какие пары имя / значение на самом деле представляют.

4 голосов
/ 27 сентября 2010

Вы можете написать себе функцию быстрого помощника:

@SuppressWarnings("unchecked")
public static <K,V> Map<K,V> ImmutableMap(Object... keyValPair){
    Map<K,V> map = new HashMap<K,V>();

    if(keyValPair.length % 2 != 0){
        throw new IllegalArgumentException("Keys and values must be pairs.");
    }

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

    return Collections.unmodifiableMap(map);
}

Обратите внимание, что приведенный выше код не остановит вас от перезаписи констант с одним и тем же именем. Использование CONST_1 нескольких мест в вашем списке приведет к появлению окончательного значения CONST_1.

Использование это что-то вроде:

Map<String,Double> constants = ImmutableMap(
    "CONST_0", 1.0,
    "CONST_1", 2.0
);
4 голосов
/ 27 сентября 2010

Извините, я тинкер.

public class MapTest {
    private static Map<String, String> map;

    static {
        Map<String, String> tmpMap = new HashMap<String, String>();

        tmpMap.put("A", "Apple");
        tmpMap.put("B", "Banana");
        // etc
        map = Collections.unmodifiableMap(tmpMap);
    }

    public Map<String, String> getMap() {
        return map;
    }
}
1 голос
/ 08 апреля 2012

Мне нравится делать объявление и инициализацию в одной строке.Я использовал эту удобную маленькую утилиту так долго, что в основном - это мой "литерал карты", и пока они не будут "правильными" в языке, я буду продолжать использовать его вот так :)

Рад поделиться этим здесь.

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * A handy utility for creating and initializing Maps in a single statement.
 * @author Jonathan Cobb. This source code is in the Public Domain.
 */
public class MapBuilder {

    /**
     * Most common create/init case. Usage:
     *
     *   Map<String, Boolean> myPremadeMap = MapBuilder.build(new Object[][]{
     *     { "a", true }, { "b", false }, { "c", true }, { "d", true },
     *     { "e", "yes, still dangerous but at least it's not an anonymous class" }
     *   });
     *
     * If your keys and values are of the same type, it will even be typesafe:
     *   Map<String, String> someProperties = MapBuilder.build(new String[][]{
     *       {"propA", "valueA" }, { "propB", "valueB" }
     *   });
     *
     * @param values [x][2] array. items at [x][0] are keys and [x][1] are values.
     * @return a LinkedHashMap (to preserve order of declaration) with the "values" mappings
     */
    public static <K,V> Map<K,V> build(Object[][] values) {
        return build(new LinkedHashMap<K,V>(), values);
    }

    /**
     * Usage:
     *  Map<K,V> myMap = MapBuilder.build(new MyMapClass(options),
     *                                    new Object[][]{ {k,v}, {k,v}, ... });
     * @param map add key/value pairs to this map
     * @return the map passed in, now containing new "values" mappings
     */
    public static <K,V> Map<K,V> build(Map<K,V> map, Object[][] values) {
        for (Object[] value : values) {
            map.put((K) value[0], (V) value[1]);
        }
        return map;
    }

    /** Same as above, for single-value maps */
    public static <K,V> Map<K,V> build(Map<K,V> map, K key, V value) {
        return build(map, new Object[][]{{key,value}});
    }

    /**
     * Usage:
     *  Map<K,V> myMap = MapBuilder.build(MyMapClass.class, new Object[][]{ {k,v}, {k,v}, ... });
     * @param mapClass a Class that implements Map
     * @return the map passed in, now containing new "values" mappings
     */
    public static <K,V> Map<K,V> build(Class<? extends Map<K,V>> mapClass, Object[][] values) {

        final Map<K,V> map;
        try { map = mapClass.newInstance(); } catch (Exception e) {
            throw new IllegalStateException("Couldn't create new instance of class: "+mapClass.getName(), e);
        }
        return build(map, values);
    }

    /** Usage: Map<K,V> myMap = MapBuilder.build(key, value); */
    public static <K,V> Map build(K key, V value) {
        Map<K,V> map = new HashMap<>();
        map.put(key, value);
        return map;
    }

}
1 голос
/ 26 сентября 2010

Хорошо, с улучшением Йорна я не могу изменить карту вообще, внутренне или внешне. Возможно, не так хорошо читаемо, но если вам нужна карта, которую нельзя изменить, я думаю, что это лучше.

public class MapTest {
    private static Map<String, String> map = initMap();

    private static Map<String, String> initMap() {
        Map<String, String> map = new HashMap<String, String>();

        map.put("A", "Apple");
        map.put("B", "Banana");
        // etc
        return Collections.unmodifiableMap(map);
    }

    public Map<String, String> getMap() {
        return map;
    }

    public static void main(String[] args) {
        MapTest m = new MapTest();
        System.out.println(m.getMap().get("A"));
        m.getMap().put("this", "that");
    }
}
1 голос
/ 26 сентября 2010

Java7 предполагает реализовать следующий синтаксис:

Map<String, String> = {
    "key1": "value",
    "key2": "value",
    "key3": "value",
    "key4": "value"
};

Однако теперь вы вынуждены использовать решения, предложенные Йорном или Тони Эннисом.

1 голос
/ 26 сентября 2010

Вот другой способ, лучше всего подходящий для карт, которые не будут меняться:

public class Whatever {
    private static Map<String,String> map = new HashMap<String,String>();

    static {
        map.put("A", "Apple");
        map.put("B", "Banana");
        // etc
    }
}
...