Как я могу инициализировать статическую карту?

Как бы вы инициализировали статическую Map в Java?

Способ первый: статический инициализатор
Способ второй: инициализатор экземпляра (анонимный подкласс) или какой-то другой метод?

Каковы плюсы и минусы каждого?

Вот пример, иллюстрирующий два метода:

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

public class Test {
    private static final Map<Integer, String> myMap = new HashMap<Integer, String>();
    static {
        myMap.put(1, "one");
        myMap.put(2, "two");
    }

    private static final Map<Integer, String> myMap2 = new HashMap<Integer, String>(){
        {
            put(1, "one");
            put(2, "two");
        }
    };
}

Ответы

Ответ 1

Инициализатор экземпляра - это просто синтаксический сахар в этом случае, верно? Я не понимаю, зачем вам нужен дополнительный анонимный класс только для инициализации. И это не сработает, если создаваемый класс является окончательным.

Вы также можете создать неизменяемую карту, используя статический инициализатор:

public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}

Ответ 2

Мне нравится Guava способ инициализации статической, неизменяемой карты:

static final Map<Integer, String> MY_MAP = ImmutableMap.of(
    1, "one",
    2, "two"
);

Как вы можете видеть, это очень красноречиво (из-за удобных методов factory в ImmutableMap).

Если вы хотите, чтобы карта имела более 5 записей, вы больше не можете использовать ImmutableMap.of(). Вместо этого попробуйте ImmutableMap.builder() в следующих строках:

static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder()
    .put(1, "one")
    .put(2, "two")
    // ... 
    .put(15, "fifteen")
    .build();

Чтобы узнать больше о преимуществах утилит универсальной коллекции Guava, см. Неизменяемые коллекции, объясненные в Руководстве пользователя Guava.

(Подмножество) Гуава раньше называлось Коллекциями Google. Если вы еще не используете эту библиотеку в своем Java-проекте, я strong рекомендую попробовать! Guava быстро стал одной из самых популярных и полезных бесплатных сторонних библиотек для Java, поскольку пользователи SO SO согласны. (Если вы новичок в этом, за этой ссылкой есть отличные учебные ресурсы.)


Обновление (2015). Что касается Java 8, я бы по-прежнему использовал подход Guava, потому что он намного чище, чем что-либо еще. Если вам не нужна зависимость от Guava, рассмотрите простой старый метод init. Взлом с двумерным массивом и Stream API довольно уродлив, если вы спросите меня и получите более уродливое, если вам нужно создать карту, ключи и значения которой не совпадают типа (например, Map<Integer, String> в вопросе).

Что касается будущего Guava в целом, то в отношении Java 8 Louis Wasserman сказал это еще в 2014 году и [обновление] в 2016 году было объявлено, что Guava 21 потребует и правильно поддерживает Java 8.


Обновление (2016): как указывает Тагир Валеев, Java 9, наконец, сделает это чистым не используя ничего, кроме чистого JDK, добавив удобные методы factory для коллекций:

static final Map<Integer, String> MY_MAP = Map.of(
    1, "one", 
    2, "two"
);

Ответ 3

Я бы использовал:

public class Test {
    private static final Map<Integer, String> MY_MAP = createMap();

    private static Map<Integer, String> createMap() {
        Map<Integer, String> result = new HashMap<Integer, String>();
        result.put(1, "one");
        result.put(2, "two");
        return Collections.unmodifiableMap(result);
    }
}
  • он избегает анонимного класса, который я лично считаю плохим, и избегаю
  • он делает создание карты более явным
  • делает карту немодифицируемой
  • поскольку MY_MAP является константой, я бы назвал его константой

Ответ 4

Java 5 предоставляет этот более компактный синтаксис:

static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
    put("Up",    "Down");
    put("Charm", "Strange");
    put("Top",   "Bottom");
}};

Ответ 5

Одним из преимуществ второго метода является то, что вы можете обернуть его с Collections.unmodifiableMap() чтобы гарантировать, что ничто не собирается обновлять коллекцию позже:

private static final Map<Integer, String> CONSTANT_MAP = 
    Collections.unmodifiableMap(new HashMap<Integer, String>() {{ 
        put(1, "one");
        put(2, "two");
    }});

 // later on...

 CONSTANT_MAP.put(3, "three"); // going to throw an exception!

Ответ 6

Вот инициализатор статической карты Java 8:

private static final Map<String, String> EXTENSION_TO_MIMETYPE =
    Arrays.stream(new String[][] {
        { "txt", "text/plain" }, 
        { "html", "text/html" }, 
        { "js", "application/javascript" },
        { "css", "text/css" },
        { "xml", "application/xml" },
        { "png", "image/png" }, 
        { "gif", "image/gif" }, 
        { "jpg", "image/jpeg" },
        { "jpeg", "image/jpeg" }, 
        { "svg", "image/svg+xml" },
    }).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));

Изменение: чтобы инициализировать Map<Integer, String> как в вопросе, вам нужно что-то вроде этого:

static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
        {1, "one"},
        {2, "two"},
}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));

Редактирование (2): существует лучшая версия с поддержкой смешанного типа от i_am_zero, которая использует поток new SimpleEntry<>(k, v). Проверьте этот ответ: fooobar.com/questions/11520/...

Ответ 7

В Java 9:

private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");

См. JEP 269 для деталей. JDK 9 поступил в продажу в сентябре 2017 года.

Ответ 8

Java 9

Мы можем использовать Map.ofEntries как:

import static java.util.Map.entry;
private static final Map<Integer,String> map = Map.ofEntries(
        entry(1, "one"),
        entry(2, "two"),
        entry(3, "three"),
        entry(4, "four"),
        entry(5, "five"),
        entry(6, "six"),
        entry(7, "seven"),
        entry(8, "eight"),
        entry(9, "nine"),
        entry(10, "ten"));

Мы также можем использовать Map.of как предложил Тагир в своем ответе здесь, но мы не можем иметь более 10 записей, использующих Map.of

Java 8 (аккуратное решение)

Мы можем создать поток записей на карте. У нас уже есть две реализации Entry в java.util.AbstractMap которые являются SimpleEntry и SimpleImmutableEntry. Для этого примера мы можем использовать первый как:

import java.util.AbstractMap.*;
private static final Map<Integer, String> myMap = Stream.of(
            new SimpleEntry<>(1, "one"),
            new SimpleEntry<>(2, "two"),
            new SimpleEntry<>(3, "three"),
            new SimpleEntry<>(4, "four"),
            new SimpleEntry<>(5, "five"),
            new SimpleEntry<>(6, "six"),
            new SimpleEntry<>(7, "seven"),
            new SimpleEntry<>(8, "eight"),
            new SimpleEntry<>(9, "nine"),
            new SimpleEntry<>(10, "ten"))
            .collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));

Ответ 9

С Eclipse Collections будет работать все следующее:

import java.util.Map;

import org.eclipse.collections.api.map.ImmutableMap;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;

public class StaticMapsTest
{
    private static final Map<Integer, String> MAP =
        Maps.mutable.with(1, "one", 2, "two");

    private static final MutableMap<Integer, String> MUTABLE_MAP =
       Maps.mutable.with(1, "one", 2, "two");


    private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();


    private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =
        Maps.mutable.with(1, "one", 2, "two").asSynchronized();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").toImmutable();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =
        Maps.immutable.with(1, "one", 2, "two");
}

Вы также можете статически инициализировать примитивные карты с коллекциями Eclipse.

import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;

public class StaticPrimitiveMapsTest
{
    private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two");

    private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asUnmodifiable();

    private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asSynchronized();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .toImmutable();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =
            IntObjectMaps.immutable.<String>empty()
                    .newWithKeyValue(1, "one")
                    .newWithKeyValue(2, "two");
} 

Примечание: я являюсь коммиттером для коллекций Eclipse

Ответ 10

Я бы никогда не создал анонимный подкласс в этой ситуации. Статические инициализаторы работают одинаково хорошо, если вы хотите сделать карту немодифицируемой, например:

private static final Map<Integer, String> MY_MAP;
static
{
    Map<Integer, String>tempMap = new HashMap<Integer, String>();
    tempMap.put(1, "one");
    tempMap.put(2, "two");
    MY_MAP = Collections.unmodifiableMap(tempMap);
}

Ответ 11

Возможно, интересно посмотреть Google Collections, например. видео, которое они имеют на своей странице. Они предоставляют различные способы инициализации карт и наборов, а также предоставляют неизменные коллекции.

Обновление: эта библиотека теперь называется Guava.

Ответ 12

Мне нравится анонимный класс, потому что с ним легко справиться:

public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
    {
        put(1, "some value");
                    //rest of code here
    }
});

Ответ 13

public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}

Если мы объявим более одной константы, тогда этот код будет записан в статическом блоке, и в будущем это будет сложно поддерживать. Поэтому лучше использовать анонимный класс.

public class Test {

    public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
        {
            put(1, "one");
            put(2, "two");
        }
    });
}

И предлагается использовать unmodifiableMap для констант, иначе он не может считаться постоянным.

Ответ 14

Я мог бы настоятельно предложить стиль "двойного выравнивания фигур" в стиле статического блока.

Кто-то может прокомментировать, что они не любят анонимный класс, накладные расходы, производительность и т.д.

Но я больше рассматриваю читаемость кода и ремонтопригодность. В этой точке зрения, у меня есть двойная фигурная скобка, это скорее стиль кода, а не статический метод.

  • Элементы являются вложенными и встроенными.
  • Это больше OO, а не процедурный.
  • влияние производительности действительно мало и может быть проигнорировано.
  • Лучшая поддержка контура IDE (а не много анонимных статических {} блоков)
  • Вы сохранили несколько строк комментария, чтобы принести им отношения.
  • Предотвращение утечки элемента/экземпляра элемента неинициализированного объекта из исключения и оптимизатора байт-кода.
  • Не беспокойтесь о порядке выполнения статического блока.

Кроме того, вы знаете GC анонимного класса, вы всегда можете преобразовать его в обычный HashMap с помощью new HashMap(Map map).

Вы можете сделать это, пока не столкнетесь с другой проблемой. Если вы это сделаете, вы должны использовать для этого еще один стиль кодирования (например, не статический класс factory).

Ответ 15

Как обычно, apache-commons имеет правильный метод MapUtils.putAll(Map, Object []):

Например, чтобы создать цветовую карту:

Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
     {"RED", "#FF0000"},
     {"GREEN", "#00FF00"},
     {"BLUE", "#0000FF"}
 });

Ответ 16

Здесь мой любимый, когда я не хочу (или не могу) использовать Guava ImmutableMap.of(), или если мне нужен изменяемый Map:

public static <A> Map<String, A> asMap(Object... keysAndValues) {
    return new LinkedHashMap<String, A>() {{
        for (int i = 0; i < keysAndValues.length - 1; i++) {
            put(keysAndValues[i].toString(), (A) keysAndValues[++i]);
        }
    }};
}

Он очень компактен и игнорирует паразитные значения (т.е. конечный ключ без значения).

Использование:

Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));

Ответ 17

Если вы хотите немодифицируемую карту, наконец, в java 9 добавлен класс factory of to Map. Аналогичный метод добавляется и в Set, List.

Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");

Ответ 18

Я предпочитаю использовать статический инициализатор, чтобы избежать генерации анонимных классов (что не имело бы дальнейшей цели), поэтому я расскажу о советах, инициализирующихся статическим инициализатором. Все перечисленные решения/советы являются безопасными по типу.

Примечание:. В вопросе ничего не говорится о том, чтобы сделать карту немодифицируемой, поэтому я оставлю это, но знаю, что ее можно легко сделать с помощью Collections.unmodifiableMap(map).

Первый совет

Первый совет: вы можете сделать локальную ссылку на карту, и вы дадите ей короткое имя:

private static final Map<Integer, String> myMap = new HashMap<>();
static {
    final Map<Integer, String> m = myMap; // Use short name!
    m.put(1, "one"); // Here referencing the local variable which is also faster!
    m.put(2, "two");
    m.put(3, "three");
}

Второй совет

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

private static final Map<Integer, String> myMap2 = new HashMap<>();
static {
    p(1, "one"); // Calling the helper method.
    p(2, "two");
    p(3, "three");
}

private static void p(Integer k, String v) {
    myMap2.put(k, v);
}

Вспомогательный метод здесь не используется повторно, поскольку он может добавлять только элементы в myMap2. Чтобы сделать его повторно используемым, мы могли бы сделать карту самой параметром вспомогательного метода, но тогда код инициализации не был бы короче.

Третий отзыв

Третий совет состоит в том, что вы можете создать класс-помощник, который можно использовать повторно, с помощью заполняющих функций. Это действительно простой, 10-строчный вспомогательный класс, который безопасен по типу:

public class Test {
    private static final Map<Integer, String> myMap3 = new HashMap<>();
    static {
        new B<>(myMap3)   // Instantiating the helper class with our map
            .p(1, "one")
            .p(2, "two")
            .p(3, "three");
    }
}

class B<K, V> {
    private final Map<K, V> m;

    public B(Map<K, V> m) {
        this.m = m;
    }

    public B<K, V> p(K k, V v) {
        m.put(k, v);
        return this; // Return this for chaining
    }
}

Ответ 19

Создаваемый вами анонимный класс хорошо работает. Однако вы должны знать, что это внутренний класс и поэтому он будет содержать ссылку на экземпляр окружающего класса. Таким образом, вы обнаружите, что не можете делать с ним определенные вещи (используя XStream для одного). Вы получите очень странные ошибки.

Сказав это, до тех пор, пока вы знаете, тогда этот подход хорош. Я использую его большую часть времени для краткой инициализации всех видов коллекций.

РЕДАКТИРОВАТЬ: правильно отметил в комментариях, что это статический класс. Очевидно, я не читал это достаточно внимательно. Однако мои комментарии все еще применимы к анонимным внутренним классам.

Ответ 20

Если вам нужно что-то кратное и относительно безопасное, вы можете просто переключить проверку типа времени компиляции на время выполнения:

static final Map<String, Integer> map = MapUtils.unmodifiableMap(
    String.class, Integer.class,
    "cat",  4,
    "dog",  2,
    "frog", 17
);

Эта реализация должна улавливать любые ошибки:

import java.util.HashMap;

public abstract class MapUtils
{
    private MapUtils() { }

    public static <K, V> HashMap<K, V> unmodifiableMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        return Collections.<K, V>unmodifiableMap(makeMap(
            keyClazz,
            valClazz,
            keyValues));
    }

    public static <K, V> HashMap<K, V> makeMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        if (keyValues.length % 2 != 0)
        {
            throw new IllegalArgumentException(
                    "'keyValues' was formatted incorrectly!  "
                  + "(Expected an even length, but found '" + keyValues.length + "')");
        }

        HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);

        for (int i = 0; i < keyValues.length;)
        {
            K key = cast(keyClazz, keyValues[i], i);
            ++i;
            V val = cast(valClazz, keyValues[i], i);
            ++i;
            result.put(key, val);
        }

        return result;
    }

    private static <T> T cast(Class<? extends T> clazz, Object object, int i)
    {
        try
        {
            return clazz.cast(object);
        }
        catch (ClassCastException e)
        {
            String objectName = (i % 2 == 0) ? "Key" : "Value";
            String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
            throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
        }
    }
}

Ответ 21

С Java 8 я пришел к использованию следующего шаблона:

private static final Map<String, Integer> MAP = Stream.of(
    new AbstractMap.SimpleImmutableEntry<>("key1", 1),
    new AbstractMap.SimpleImmutableEntry<>("key2", 2)
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Это не самый короткий и немного окольный, но

  • он не требует ничего вне java.util
  • он типирует и легко вмещает разные типы ключей и значений.

Ответ 22

Если вам нужно добавить только одно значение на карту, вы можете использовать Collections.singletonMap:

Map<K, V> map = Collections.singletonMap(key, value)

Ответ 23

Вы можете использовать StickyMap и MapEntry from Cactoos:

private static final Map<String, String> MAP = new StickyMap<>(
  new MapEntry<>("name", "Jeffrey"),
  new MapEntry<>("age", "35")
);

Ответ 24

Мне не нравится синтаксис статического инициализатора, и я не уверен в анонимных подклассах. Как правило, я согласен со всеми минусами использования статических инициализаторов и всех недостатков использования анонимных подклассов, которые были упомянуты в ответах предыдущего. С другой стороны - профессионалов, представленных на этих постах, недостаточно для меня. Я предпочитаю использовать статический метод инициализации:

public class MyClass {
    private static final Map<Integer, String> myMap = prepareMap();

    private static Map<Integer, String> prepareMap() {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "one");
        hashMap.put(2, "two");

        return hashMap;
    }
}

Ответ 25

Я не видел того подхода, который я использую (и стал любить), размещенного в любых ответах, так что вот оно:

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

вместо этого, я предпочитаю инициализацию, которая выглядит так:

map(
    entry("keyA", "val1"),
    entry("keyB", "val2"),
    entry("keyC", "val3")
);

К сожалению, эти методы не являются частью стандартной библиотеки Java, поэтому вам нужно будет создать (или использовать) библиотеку утилиты, которая определяет следующие методы:

 public static <K,V> Map<K,V> map(Map.Entry<K, ? extends V>... entries)
 public static <K,V> Map.Entry<K,V> entry(K key, V val)

(вы можете использовать "import static", чтобы избежать необходимости префикса имени метода)

Мне было полезно предоставить аналогичные статические методы для других коллекций (список, набор, sortedSet, sortedMap и т.д.)

Это не так хорошо, как инициализация объекта json, но это шаг в этом направлении, насколько читаемость.

Ответ 26

Поскольку Java не поддерживает картографические литералы, экземпляры карт всегда должны быть явно созданы и заполнены.

К счастью, с помощью методов factory можно аппроксимировать поведение литералов в Java.

Например:

public class LiteralMapFactory {

    // Creates a map from a list of entries
    @SafeVarargs
    public static <K, V> Map<K, V> mapOf(Map.Entry<K, V>... entries) {
        LinkedHashMap<K, V> map = new LinkedHashMap<>();
        for (Map.Entry<K, V> entry : entries) {
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }
    // Creates a map entry
    public static <K, V> Map.Entry<K, V> entry(K key, V value) {
        return new AbstractMap.SimpleEntry<>(key, value);
    }

    public static void main(String[] args) {
        System.out.println(mapOf(entry("a", 1), entry("b", 2), entry("c", 3)));
    }
}

Вывод:

{a = 1, b = 2, c = 3}

Это намного удобнее, чем создание и заполнение карты элементом за раз.

Ответ 27

Ваш второй подход (инициализация двойной скобки) считается анти-паттерном, поэтому я бы остановился на первом подходе.

Другой простой способ инициализации статической карты - использование этой служебной функции:

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

    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 = mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = mapOf("key1", "value1", "key2", "value2");

Примечание: в Java 9 вы можете использовать Map.of

Ответ 28

Я прочитал ответы и решил написать свой собственный конструктор карт. Не стесняйтесь копировать-вставить и наслаждаться.

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * A tool for easy creation of a map. Code example:<br/>
 * {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}
 * @param <K> key type (inferred by constructor)
 * @param <V> value type (inferred by constructor)
 * @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)
 */
public class MapBuilder <K, V> {
    private Map<K, V> map = new HashMap<>();

    /** Constructor that also enters the first entry. */
    private MapBuilder(K key, V value) {
        and(key, value);
    }

    /** Factory method that creates the builder and enters the first entry. */
    public static <A, B> MapBuilder<A, B> mapOf(A key, B value) {
        return new MapBuilder<>(key, value);
    }

    /** Puts the key-value pair to the map and returns itself for method chaining */
    public MapBuilder<K, V> and(K key, V value) {
        map.put(key, value);
        return this;
    }

    /**
     * If no reference to builder is kept and both the key and value types are immutable,
     * the resulting map is immutable.
     * @return contents of MapBuilder as an unmodifiable map.
     */
    public Map<K, V> build() {
        return Collections.unmodifiableMap(map);
    }
}

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

Не EDIT2: Еще совсем недавно, я уже не как статический метод, называемый of, как это выглядит довольно плохо при использовании статического импорта. mapOf этого я переименовал его в mapOf, что сделало его более подходящим для статического импорта.

Ответ 29

JEP 269 предоставляет некоторые удобные методы factory для API коллекций. Эти методы factory не находятся в текущей версии Java, которая составляет 8, но планируются для выпуска Java 9.

Для Map существуют два метода factory: of и ofEntries. Используя of, вы можете передавать пары переменных/ключей. Например, чтобы создать Map как {age: 27, major: cs}:

Map<String, Object> info = Map.of("age", 27, "major", "cs");

В настоящее время существует десять перегруженных версий для of, поэтому вы можете создать карту, содержащую десять пар ключ/значение. Если вам не нравится это ограничение или переменный ключ/значения, вы можете использовать ofEntries:

Map<String, Object> info = Map.ofEntries(
                Map.entry("age", 27),
                Map.entry("major", "cs")
);

Оба of и ofEntries возвращают неизменяемый Map, поэтому вы не сможете изменить их элементы после построения. Вы можете попробовать эти функции, используя JDK 9 Early Access.

Ответ 30

Ну... Мне нравятся перечисления;)

enum MyEnum {
    ONE   (1, "one"),
    TWO   (2, "two"),
    THREE (3, "three");

    int value;
    String name;

    MyEnum(int value, String name) {
        this.value = value;
        this.name = name;
    }

    static final Map<Integer, String> MAP = Stream.of( values() )
            .collect( Collectors.toMap( e -> e.value, e -> e.name ) );
}