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

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

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

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

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

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

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

    private static final Map myMap2 = new HashMap(){
        {
            put(1, "one");
            put(2, "two");
        }
    };
}
вопрос задан 3.02.2009
dogbane
182681 репутация

41 ответов


  • 961 рейтинг

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

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

    public class Test {
        private static final Map myMap;
        static {
            Map aMap = ....;
            aMap.put(1, "one");
            aMap.put(2, "two");
            myMap = Collections.unmodifiableMap(aMap);
        }
    }
    
    ответ дан Miserable Variable, с репутацией 23160, 3.02.2009
  • 377 рейтинг

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

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

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

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

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

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

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


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

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


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

    static final Map MY_MAP = Map.of(
        1, "one", 
        2, "two"
    );
    
    ответ дан Jonik, с репутацией 49949, 31.08.2011
  • 162 рейтинг

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

    public class Test {
        private static final Map MY_MAP = createMap();
    
        private static Map createMap() {
            Map result = new HashMap();
            result.put(1, "one");
            result.put(2, "two");
            return Collections.unmodifiableMap(result);
        }
    }
    
    1. это избегает анонимного класса, который я лично считаю плохим стилем, и избегаю
    2. это делает создание карты более явным
    3. делает карту неизменной
    4. , поскольку MY_MAP является константой, я бы назвал ее константой
    ответ дан Peter Štibraný, с репутацией 26618, 3.02.2009
  • 158 рейтинг

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

    static final Map FLAVORS = new HashMap() {{
        put("Up",    "Down");
        put("Charm", "Strange");
        put("Top",   "Bottom");
    }};
    
    ответ дан Chris Noe, с репутацией 17636, 15.07.2009
  • 81 рейтинг

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

    private static final Map CONSTANT_MAP = 
        Collections.unmodifiableMap(new HashMap() {{ 
            put(1, "one");
            put(2, "two");
        }});
    
     // later on...
    
     CONSTANT_MAP.put(3, "three"); // going to throw an exception!
    
    ответ дан Outlaw Programmer, с репутацией 8081, 3.02.2009
  • 55 рейтинг

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

    private static final Map 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, как в вопросе, вам нужно что-то вроде этого:

    static final Map 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). Проверьте этот ответ: https: // stackoverflow. com / a / 37384773/3950982

    ответ дан Luke Hutchison, с репутацией 2613, 14.09.2014
  • 43 рейтинг

    В Java 9: ​​

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

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

    ответ дан Tagir Valeev, с репутацией 65050, 29.12.2015
  • 27 рейтинг

    С коллекциями Eclipse (ранее коллекций GS ) будет работать все следующее:

    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 MAP =
            Maps.mutable.with(1, "one", 2, "two");
    
        private static final MutableMap MUTABLE_MAP =
           Maps.mutable.with(1, "one", 2, "two");
    
    
        private static final MutableMap UNMODIFIABLE_MAP =
            Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();
    
    
        private static final MutableMap SYNCHRONIZED_MAP =
            Maps.mutable.with(1, "one", 2, "two").asSynchronized();
    
    
        private static final ImmutableMap IMMUTABLE_MAP =
            Maps.mutable.with(1, "one", 2, "two").toImmutable();
    
    
        private static final ImmutableMap IMMUTABLE_MAP2 =
            Maps.immutable.with(1, "one", 2, "two");
    }
    

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

    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 MUTABLE_INT_OBJ_MAP =
                IntObjectMaps.mutable.empty()
                        .withKeyValue(1, "one")
                        .withKeyValue(2, "two");
    
        private static final MutableIntObjectMap UNMODIFIABLE_INT_OBJ_MAP =
                IntObjectMaps.mutable.empty()
                        .withKeyValue(1, "one")
                        .withKeyValue(2, "two")
                        .asUnmodifiable();
    
        private static final MutableIntObjectMap SYNCHRONIZED_INT_OBJ_MAP =
                IntObjectMaps.mutable.empty()
                        .withKeyValue(1, "one")
                        .withKeyValue(2, "two")
                        .asSynchronized();
    
        private static final ImmutableIntObjectMap IMMUTABLE_INT_OBJ_MAP =
                IntObjectMaps.mutable.empty()
                        .withKeyValue(1, "one")
                        .withKeyValue(2, "two")
                        .toImmutable();
    
        private static final ImmutableIntObjectMap IMMUTABLE_INT_OBJ_MAP2 =
                IntObjectMaps.immutable.empty()
                        .newWithKeyValue(1, "one")
                        .newWithKeyValue(2, "two");
    } 
    

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

    ответ дан Donald Raab, с репутацией 3976, 18.12.2012
  • 24 рейтинг

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

    private static final Map MY_MAP;
    static
    {
        MaptempMap = new HashMap();
        tempMap.put(1, "one");
        tempMap.put(2, "two");
        MY_MAP = Collections.unmodifiableMap(tempMap);
    }
    
    ответ дан eljenso, с репутацией 11795, 3.02.2009
  • 15 рейтинг

    Существует ответ 4057732480 , предложенный Люком, который инициализирует карту с использованием Java 8, но ИМХО это выглядит уродливо и трудно для чтения. Мы можем создать поток записей на карте. У нас уже есть две реализации Entry в java.util.AbstractMap, которые являются SimpleEntry и SimpleImmutableEntry . Для этого примера мы можем использовать первый как:

    import java.util.AbstractMap.*;
    private static final Map 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));
    

    Для Java 9 мы также можем использовать Map.of, как предложил Тагир в своем ответе здесь .

    ответ дан i_am_zero, с репутацией 10225, 23.05.2016
  • 14 рейтинг

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

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

    ответ дан Kaarel, с репутацией 8940, 3.02.2009
  • 14 рейтинг

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

    public static final Map
     numbers = Collections.unmodifiableMap(new HashMap() {
        {
            put(1, "some value");
                        //rest of code here
        }
    });
    
    ответ дан Shushant, с репутацией 1424, 19.09.2013
  • 9 рейтинг
    public class Test {
        private static final Map myMap;
        static {
            Map 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 для констант, иначе он не может рассматриваться как константа.

    ответ дан Leninkumar Koppoju, с репутацией 259, 3.06.2010
  • 7 рейтинг

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

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

    Map colorMap = MapUtils.putAll(new HashMap(), new String[][] {
         {"RED", "#FF0000"},
         {"GREEN", "#00FF00"},
         {"BLUE", "#0000FF"}
     });
    
    ответ дан agad, с репутацией 1659, 8.09.2015
  • 7 рейтинг

    Я мог бы настоятельно рекомендовать стиль «инициализация двойной скобкой» над стилем статического блока.

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

    Но что я больше рассматриваю, так это читаемость кода и удобство обслуживания. С этой точки зрения, я считаю, что двойная скобка - лучший стиль кода, а не статический метод.

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

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

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

    ответ дан Dennis C, с репутацией 19258, 12.12.2010
  • 5 рейтинг

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

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

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

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

    Map one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
    Map two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));
    
    ответ дан neu242, с репутацией 8467, 15.09.2016
  • 5 рейтинг

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

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

    ответ дан Bharanidharan K, с репутацией 321, 26.11.2017
  • 4 рейтинг

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

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

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

    ответ дан Brian Agnew, с репутацией 222977, 3.02.2009
  • 3 рейтинг

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

    static final Map 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  HashMap unmodifiableMap(
                Class
     keyClazz,
                Class
     valClazz,
                Object...keyValues)
        {
            return Collections.unmodifiableMap(makeMap(
                keyClazz,
                valClazz,
                keyValues));
        }
    
        public static  HashMap makeMap(
                Class
     keyClazz,
                Class
     valClazz,
                Object...keyValues)
        {
            if (keyValues.length % 2 != 0)
            {
                throw new IllegalArgumentException(
                        "'keyValues' was formatted incorrectly!  "
                      + "(Expected an even length, but found '" + keyValues.length + "')");
            }
    
            HashMap result = new HashMap(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 cast(Class
     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);
            }
        }
    }
    
    ответ дан Philip, с репутацией 905, 2.08.2013
  • 3 рейтинг

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

    private static final Map MAP = new StickyMap<>(
      new MapEntry<>("name", "Jeffrey"),
      new MapEntry<>("age", "35")
    );
    
    ответ дан yegor256, с репутацией 53954, 20.06.2017
  • 3 рейтинг

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

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

    Это не самая лаконичная и немного окольная, но

    • ничего не требуется, кроме java.util
    • , он безопасен и легко приспосабливается к различным типам ключей и значений.
    ответ дан zrvan, с репутацией 4538, 20.11.2015
  • 3 рейтинг

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

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

    Первый совет

    Первый совет: вы можете сделать локальную ссылку на карту и дать ей КРАТКОЕ имя:

    private static final Map myMap = new HashMap<>();
    static {
        final Map 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 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 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 {
        private final Map m;
    
        public B(Map m) {
            this.m = m;
        }
    
        public B p(K k, V v) {
            m.put(k, v);
            return this; // Return this for chaining
        }
    }
    
    ответ дан icza, с репутацией 150119, 22.04.2014
  • 2 рейтинг

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

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

    public static  Map mapOf(Object... keyValues) {
        Map 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 map1 = mapOf(1, "value1", 2, "value2");
    Map map2 = mapOf("key1", "value1", "key2", "value2");
    

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

    ответ дан R. Oosterholt, с репутацией 4837, 23.05.2017
  • 2 рейтинг

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

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

    Например:

    public class LiteralMapFactory {
    
        // Creates a map from a list of entries
        @SafeVarargs
        public static  Map mapOf(Map.Entry... entries) {
            LinkedHashMap map = new LinkedHashMap<>();
            for (Map.Entry entry : entries) {
                map.put(entry.getKey(), entry.getValue());
            }
            return map;
        }
        // Creates a map entry
        public static  Map.Entry 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}

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

    ответ дан nazar_art, с репутацией 6155, 26.02.2016
  • 2 рейтинг

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

    public class MyClass {
        private static final Map myMap = prepareMap();
    
        private static Map prepareMap() {
            Map hashMap = new HashMap<>();
            hashMap.put(1, "one");
            hashMap.put(2, "two");
    
            return hashMap;
        }
    }
    
    ответ дан Stanisław Borowy, с репутацией 31, 27.08.2012
  • 1 рейтинг

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

    Map map = Collections.singletonMap(key, value)
    
    ответ дан Stromata, с репутацией 133, 30.04.2017
  • 1 рейтинг

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

    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * A tool for easy creation of a map. Code example:
    * {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()} * @param key type (inferred by constructor) * @param value type (inferred by constructor) * @author Vlasec (for http://stackoverflow.com/a/30345279/1977151) */ public class MapBuilder { private Map 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 MapBuilder of(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 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 build() { return Collections.unmodifiableMap(map); } }

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

    ответ дан Vlasec, с репутацией 3202, 20.05.2015
  • 1 рейтинг

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

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

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

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

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

     public static  Map map(Map.Entry... entries)
     public static  Map.Entry entry(K key, V val)
    

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

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

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

    ответ дан josh, с репутацией 126, 3.06.2015
  • 1 рейтинг

    JEP 269 предоставляет некоторые удобные фабричные методы для API коллекций. Методы этой фабрики отсутствуют в текущей версии Java, которая составляет 8, но запланированы для выпуска Java 9.

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

    Map info = Map.of("age", 27, "major", "cs");
    

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

    Map info = Map.ofEntries(
                    Map.entry("age", 27),
                    Map.entry("major", "cs")
    );
    

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

    ответ дан Ali Dehghani, с репутацией 23805, 10.04.2016
  • 1 рейтинг

    Хорошо. , , Я люблю enums;)

    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 MAP = Stream.of( values() )
                .collect( Collectors.toMap( e -> e.value, e -> e.name ) );
    }
    
    ответ дан jglatre, с репутацией 491, 25.10.2017
  • 0 рейтинг

    В Java 8 процедурный подход также может быть заключен в Supplier:

    Map m = ((Supplier>)(() -> { Map result = new HashMap<>(); result.put("foo","hoo"); ... return result; )).get(); 

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

    ответ дан Tomáš Záluský, с репутацией 1280, 6.08.2015
  • 0 рейтинг

    Даже с хорошим классом Gumm ImmutableMap иногда я хотел бы свободно создавать изменяемую карту. Я обнаружил, что хочу избежать статических блоков и усилителей. анонимный подтип, когда появилась Java 8, я написал крошечную библиотеку 3443070150 Fluent .

    // simple usage, assuming someMap is a Map already declared
    Map example = new Fluent.HashMap()
        .append("key1", "val1")
        .append("key2", "val2")
        .appendAll(someMap);
    

    С интерфейсом Java 8 по умолчанию я мог реализовать Fluent. Методы отображения для всех стандартных реализаций Java Map (например, HashMap, ConcurrentSkipListMap,. , , и т. д.) без утомительного повторения.

    Не изменяемые карты тоже просты.

    Map immutable = new Fluent.LinkedHashMap()
        .append("one", 1)
        .append("two", 2)
        .append("three", 3)
        .unmodifiable();
    

    См. https: // github. com / alexheretic / fluent для источника, документации и примеров.

    ответ дан Alex Butler, с репутацией 196, 30.11.2016
  • 0 рейтинг

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

            Map myMap = hashMap(
                    bob -> 5,
                    TheGimp -> 8,
                    incredibleKoolAid -> "James Taylor",
                    heyArnold -> new Date()
            );
    
            Map typesafeMap = treeMap(
                    a -> 5,
                    bee -> 8,
                    sea -> 13
                    deep -> 21
            );
    

    Пример непроверенного кода на https: // gist. GitHub. com / galdosd / 10823529 Было бы любопытно мнение других по этому поводу (это слегка зло. , , )

    ответ дан Domingo Ignacio, с репутацией 1054, 16.04.2014
  • 0 рейтинг

    Если вы можете использовать строковое представление ваших данных, эта опция также доступна в Java 8:

    static Map MAP = Stream.of(
            "1=one",
            "2=two"
    ).collect(Collectors.toMap(k -> Integer.parseInt(k.split("=")[0]), v -> v.split("=")[1]));
    
    ответ дан Christian Ullenboom, с репутацией 755, 13.01.2014
  • 0 рейтинг

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

    Например:

    public abstract class Shape {
    
        public static final String COLOR_KEY = "color_key";
        public static final String OPAQUE_KEY = "opaque_key";
    
        private final String color;
        private final Boolean opaque;
    
        /**
         * Initializing constructor - note no default constructor.
         *
         * @param properties a collection of Shape properties
         */
        public Shape(Map properties) {
            color = ((String) properties.getOrDefault(COLOR_KEY, "black"));
            opaque = (Boolean) properties.getOrDefault(OPAQUE_KEY, false);
        }
    
        /**
         * Color property accessor method.
         *
         * @return the color of this Shape
         */
        public String getColor() {
            return color;
        }
    
        /**
         * Opaque property accessor method.
         *
         * @return true if this Shape is opaque, false otherwise
         */
        public Boolean isOpaque() {
            return opaque;
        }
    }
    

    и моя конкретная реализация этого класса - но он хочет / нуждается в конструкторе по умолчанию:

    public class SquareShapeImpl extends Shape {
    
        private static final Map DEFAULT_PROPS = new HashMap<>();
    
        static {
            DEFAULT_PROPS.put(Shape.COLOR_KEY, "yellow");
            DEFAULT_PROPS.put(Shape.OPAQUE_KEY, false);
        }
    
        /**
         * Default constructor -- intializes this square to be a translucent yellow
         */
        public SquareShapeImpl() {
            // the static initializer was useful here because the call to 
            // this(...) must be the first statement in this constructor
            // i.e., we can't be mucking around and creating a map here
            this(DEFAULT_PROPS);
        }
    
        /**
         * Initializing constructor -- create a Square with the given
         * collection of properties.
         *
         * @param props a collection of properties for this SquareShapeImpl
         */
        public SquareShapeImpl(Map props) {
            super(props);
        }
    }
    

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

    public class StaticInitDemo {
    
        public static void main(String[] args) {
    
            // create a translucent, yellow square...
            Shape defaultSquare = new SquareShapeImpl();
    
            // etc...
        }
    }
    
    ответ дан Jim Daehn, с репутацией 90, 28.01.2015
  • 0 рейтинг

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

    ответ дан Chase Seibert, с репутацией 12177, 3.02.2009
  • 0 рейтинг

    Вот код от AbacusUtil

    Map map = N.asMap(1, "one", 2, "two");
    // Or for Immutable map 
    ImmutableMap = ImmutableMap.of(1, "one", 2, "two");
    

    Декларация: я разработчик AbacusUtil.

    ответ дан user_3380739, с репутацией 783, 28.11.2016
  • 0 рейтинг

    Примечание. Этот ответ фактически относится к вопросу Как напрямую инициализировать HashMap (в буквальном смысле)? но так как он помечен как [дубликат] этого. , ,


    До Java 9 с ее картой . из () (который также ограничен 10 отображениями) вы можете расширить реализацию Map по вашему выбору, e. г. :

    public class InitHashMap extends HashMap
    

    повторно реализовать конструкторов HashMap:

    public InitHashMap() {
        super();
    }
    
    public InitHashMap( int initialCapacity, float loadFactor ) {
        super( initialCapacity, loadFactor );
    }
    
    public InitHashMap( int initialCapacity ) {
        super( initialCapacity );
    }
    
    public InitHashMap( Map
     m ) {
        super( m );
    }
    

    и добавьте дополнительный конструктор, который вдохновлен ответом Aerthel , но является общим с использованием типов Object... и :

    public InitHashMap( final Object... keyValuePairs ) {
    
        if ( keyValuePairs.length % 2 != 0 )
            throw new IllegalArgumentException( "Uneven number of arguments." );
    
        K key = null;
        int i = -1;
    
        for ( final Object keyOrValue : keyValuePairs )
            switch ( ++i % 2 ) {
                case 0:  // key
                    if ( keyOrValue == null )
                        throw new IllegalArgumentException( "Key[" + (i >> 1) + "] is ." );
                    key = (K) keyOrValue;
                    continue;
                case 1:  // value
                    put( key, (V) keyOrValue );
            }
    }
    

    Пробег

    public static void main( final String[] args ) {
    
        final Map map = new InitHashMap<>( 1, "First", 2, "Second", 3, "Third" );
        System.out.println( map );
    }
    

    Выход

    {1=First, 2=Second, 3=Third}
    

    Вы также можете расширить интерфейс Map:

    public interface InitMap extends Map {
    
        static  Map of( final Object... keyValuePairs ) {
    
            if ( keyValuePairs.length % 2 != 0 )
                throw new IllegalArgumentException( "Uneven number of arguments." );
    
            final Map map = new HashMap<>( keyValuePairs.length >> 1, .75f );
            K key = null;
            int i = -1;
    
            for ( final Object keyOrValue : keyValuePairs )
                switch ( ++i % 2 ) {
                    case 0: // key
                        if ( keyOrValue == null )
                            throw new IllegalArgumentException( "Key[" + (i >> 1) + "] is ." );
                        key = (K) keyOrValue;
                        continue;
                    case 1: // value
                        map.put( key, (V) keyOrValue );
                }
            return map;
        }
    }
    

    Пробег

    public static void main( final String[] args ) {
    
        System.out.println( InitMap.of( 1, "First", 2, "Second", 3, "Third" ) );
    }
    

    Выход

    {1=First, 2=Second, 3=Third}
    
    ответ дан Gerold Broser, с репутацией 7299, 10.09.2018
  • 0 рейтинг

    Я сделал что-то немного другое. Не самый лучший, но у меня это работает. Возможно это могло быть "обобщено".

    private static final Object[][] ENTRIES =
    {
      {new Integer(1), "one"},
      {new Integer(2), "two"},
    };
    private static final Map myMap = newMap(ENTRIES);
    
    private static Map newMap(Object[][] entries)
    {
      Map map = new HashMap();
    
      for (int x = 0; x < entries.length; x++)
      {
        Object[] entry = entries[x];
    
        map.put(entry[0], entry[1]);
      }
    
      return map;
    }
    
    ответ дан Gary Kephart, с репутацией 3190, 3.02.2009
  • 0 рейтинг

    Здесь есть несколько хороших ответов, но я хочу предложить еще один.

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

    Вот мой метод newMap:

    public class CollectionUtils {
        public static Map newMap(Object... keyValuePairs) {
            Map map = new HashMap();
            if ( keyValuePairs.length % 2 == 1 ) throw new IllegalArgumentException("Must have even number of arguments");
            for ( int i=0; i

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

    import static CollectionUtils.newMap;
    // ...
    Map aMap = newMap("key1", 1.23, "key2", 2.34);
    Map bMap = newMap(objKey1, objVal1, objKey2, objVal2, objKey3, objVal3);
    // etc...
    

    Он не использует универсальные шаблоны, но вы можете ввести карту по своему усмотрению (просто убедитесь, что вы правильно ее ввели! )

    Map aMap = (Map)newMap("key1", 1.23, "key2", 2.34);
    
    ответ дан Jason, с репутацией 6026, 28.01.2016
  • 0 рейтинг

    Второй метод может вызывать защищенные методы при необходимости. Это может быть полезно для инициализации классов, которые являются неизменяемыми после построения.

    ответ дан Mark Renouf, с репутацией 21632, 3.02.2009