Как бы вы инициализировали статический Map
в Java?
Метод один: статический инициализатор
Метод два: экземпляр инициализатора (анонимный подкласс) или какой-то другой метод?
Каковы плюсы и минусы каждого?
Вот пример, иллюстрирующий два метода:
import java.util.HashMap;
import java.util.Map;
public class Test {
private static final Map<Integer, String> myMap = new HashMap<>();
static {
myMap.put(1, "one");
myMap.put(2, "two");
}
private static final Map<Integer, String> myMap2 = new HashMap<>(){
{
put(1, "one");
put(2, "two");
}
};
}
Map.of
другоеMap.ofEntries
, проверьте stackoverflow.com/a/37384773/1216775Ответы:
Инициализатор экземпляра - это просто синтаксический сахар в этом случае, верно? Я не понимаю, зачем вам нужен дополнительный анонимный класс только для инициализации. И это не сработает, если создаваемый класс является окончательным.
Вы также можете создать неизменяемую карту, используя статический инициализатор:
источник
Мне нравится гуавский способ инициализации статической неизменной карты:
Как видите, он очень лаконичен (из-за удобных заводских методов
ImmutableMap
).Если вы хотите, чтобы на карте было более 5 записей, вы больше не можете использовать
ImmutableMap.of()
. Вместо этого попробуйтеImmutableMap.builder()
следующие строки:Чтобы узнать больше о преимуществах неизменяемых утилит сбора Guava, см. Раздел «Неизменяемые коллекции» в руководстве пользователя Guava .
(Подмножество) Гуава раньше назывался Google Collections . Если вы еще не используете эту библиотеку в своем проекте Java, я настоятельно рекомендую попробовать! Guava быстро стал одним из самых популярных и полезных бесплатных сторонних библиотек для Java, как соглашаются другие пользователи SO . (Если вы новичок в этом, за этой ссылкой есть несколько отличных учебных ресурсов.)
Обновление (2015) : Что касается Java 8 , я бы по-прежнему использовал подход Guava, потому что он намного чище, чем все остальное. Если вам не нужна зависимость от Guava, рассмотрите простой старый метод init . Хак с двумерным массивом и Stream API довольно уродлив, если вы спросите меня, и уродлив, если вам нужно создать карту, чьи ключи и значения не одного типа (как
Map<Integer, String>
в вопросе).Что касается будущего Guava в целом, что касается Java 8, Луи Вассерман сказал об этом еще в 2014 году, а [ обновление ] в 2016 году было объявлено, что Guava 21 потребует и должным образом поддержит Java 8 .
Обновление (2016) : Как отмечает Тагир Валеев , Java 9 , наконец, сделает эту задачу чистой, используя только чистый JDK, добавив удобные фабричные методы для коллекций:
источник
Я хотел бы использовать:
источник
Java 5 предоставляет этот более компактный синтаксис:
источник
HashMap implements Serializable
. Поскольку вы фактически создаете подкласс HashMap, используя этот «трюк», вы неявно создаете класс Serializable. И для этого вы должны предоставить serialUID.Double brace initialization can cause memory leaks when used from a non-static context, because the anonymous class created will maintain a reference to the surrounding object. It has worse performance than regular initialization because of the additional class loading required. It can cause equals() comparisons to fail, if the equals() method does not accept subclasses as parameter. And finally, pre Java 9 it cannot be combined with the diamond operator, because that cannot be used with anonymous classes.
- IntelliJHashMap.equals
определяется в любом подклассе MapAbstractMap
и работает с ним , поэтому здесь это не касается. Оператор с бриллиантами раздражает, но, как уже упоминалось, теперь решен.Одним из преимуществ второго метода является то, что вы можете обернуть его,
Collections.unmodifiableMap()
чтобы гарантировать, что ничто не собирается обновлять коллекцию позже:источник
Вот однострочный инициализатор статической карты Java 8:
Изменить: чтобы инициализировать
Map<Integer, String>
как в вопросе, вам нужно что-то вроде этого:Редактировать (2): Существует лучшая версия с поддержкой смешанного типа от i_am_zero, которая использует поток
new SimpleEntry<>(k, v)
вызовов. Проверьте этот ответ: https://stackoverflow.com/a/37384773/3950982источник
String[][]
не будет делать,Object[][]
это необходимо). ИМХО, этот подход уродлив (даже в большей степени с кастами) и его трудно запомнить; не буду использовать это сам.Map.of
в Java 9+См. JEP 269 для деталей. JDK 9 поступил в продажу в сентябре 2017 года.
источник
Map.ofEntries
Java 9
Мы можем использовать
Map.ofEntries
, позвонив,Map.entry( k , v )
чтобы создать каждую запись.Мы также можем использовать,
Map.of
как предложил Тагир в своем ответе здесь, но мы не можем использовать более 10 записейMap.of
.Java 8 (аккуратное решение)
Мы можем создать поток записей на карте. У нас уже есть две реализации,
Entry
вjava.util.AbstractMap
которых SimpleEntry и SimpleImmutableEntry . Для этого примера мы можем использовать первый как:источник
new SimpleEntry<>()
Путь гораздо менее читабельным , чем статическиеput()
: /С Eclipse Collections будет работать все следующее:
Вы также можете статически инициализировать примитивные карты с коллекциями Eclipse.
Примечание: я являюсь коммиттером для коллекций Eclipse
источник
Я бы никогда не создал анонимный подкласс в этой ситуации. Статические инициализаторы работают одинаково хорошо, если вы хотите сделать карту не изменяемой, например:
источник
Может быть, интересно проверить Коллекции Google , например, видео, которые они имеют на своей странице. Они предоставляют различные способы инициализации карт и наборов, а также предоставляют неизменные коллекции.
Обновление: эта библиотека теперь называется Guava .
источник
Мне нравится анонимный класс, потому что с ним легко иметь дело:
источник
Если мы объявим более одной константы, тогда этот код будет записан в статическом блоке, и это будет трудно поддерживать в будущем. Так что лучше использовать анонимный класс.
И предлагается использовать unmodifiableMap для констант, иначе он не может рассматриваться как константа.
источник
Я мог бы настоятельно рекомендовать стиль «инициализация двойной скобкой» вместо стиля статического блока.
Кто-то может прокомментировать, что ему не нравятся анонимный класс, накладные расходы, производительность и т. Д.
Но то, что я больше рассматриваю, - это удобочитаемость кода и удобство сопровождения. С этой точки зрения, я считаю, что двойная скобка - лучший стиль кода, а не статический метод.
Кроме того, если вы знаете GC анонимного класса, вы всегда можете преобразовать его в обычный HashMap с помощью
new HashMap(Map map)
.Вы можете делать это, пока не столкнетесь с другой проблемой. Если вы это сделаете, вы должны использовать для этого другой стиль кодирования (например, без статического, заводского класса).
источник
Как обычно, apache-commons имеет правильный метод MapUtils.putAll (Map, Object []) :
Например, чтобы создать цветную карту:
источник
Arrays.asMap( ... )
в простой Java я думаю, что это лучшее решение. Изобретать колесо обычно глупо. Очень слабым недостатком является то, что с дженериками потребуется непроверенное преобразование.SuppressWarnings( unchecked )
в Eclipse с такой строкой, какMap<String, String> dummy = MapUtils.putAll(new HashMap<String, String>(), new Object[][]... )
String[][]
я получаю "предупреждение"! И, конечно, это работает, только если выK
и одинV
и тот же класс. Я так понимаю, вы (понятно) не установили «непроверенное преобразование» в «Игнорировать» в настройках Eclipse?Вот мой любимый, когда я не хочу (или не могу) использовать Guava
ImmutableMap.of()
, или если мне нужен изменчивыйMap
:Он очень компактен и игнорирует случайные значения (т. Е. Конечный ключ без значения).
Применение:
источник
Если вы хотите неизменяемую карту, наконец, Java 9 добавил классный метод фабрики
of
дляMap
интерфейса. Аналогичный метод добавлен в Set, List, а также.Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");
источник
Я предпочитаю использовать статический инициализатор, чтобы избежать генерации анонимных классов (что не имело бы никакой дальнейшей цели), поэтому я перечислю советы по инициализации со статическим инициализатором. Все перечисленные решения / советы являются типобезопасными.
Примечание: в этом вопросе ничего не говорится о том, чтобы сделать карту не изменяемой, поэтому я это опущу, но знаю, что это легко сделать
Collections.unmodifiableMap(map)
.Первый совет
Первый совет: вы можете сделать локальную ссылку на карту и дать ей короткое имя:
Второй совет
Второй совет: вы можете создать вспомогательный метод для добавления записей; Вы также можете сделать этот вспомогательный метод общедоступным, если хотите:
Вспомогательный метод здесь не может использоваться повторно, потому что он может добавлять только элементы
myMap2
. Чтобы сделать его многократно используемым, мы можем сделать саму карту параметром вспомогательного метода, но тогда код инициализации не будет короче.Третий совет
Третий совет заключается в том, что вы можете создать многократно используемый вспомогательный класс, похожий на конструктор, с заполненной функциональностью. Это действительно простой 10-строчный вспомогательный класс, который безопасен для типов:
источник
Создаваемый вами анонимный класс хорошо работает. Однако вы должны знать, что это внутренний класс, и поэтому он будет содержать ссылку на экземпляр окружающего класса. Таким образом, вы обнаружите, что не можете делать с ним определенные вещи (используя XStream для одного). Вы получите очень странные ошибки.
Сказав это, до тех пор, пока вы знаете, тогда этот подход хорош. Я использую его большую часть времени для краткой инициализации всех видов коллекций.
РЕДАКТИРОВАТЬ: правильно отметил в комментариях, что это статический класс. Очевидно, я не читал это достаточно внимательно. Однако мои комментарии все еще применимы к анонимным внутренним классам.
источник
Если вам нужно что-то лаконичное и относительно безопасное, вы можете просто перенести проверку типов во время компиляции во время выполнения:
Эта реализация должна отлавливать любые ошибки:
источник
В Java 8 я использовал следующий шаблон:
Это не самое лаконичное и немного окольное, но
java.util
источник
toMap
подпись, включая поставщика карты, чтобы указать тип карты.Если вам нужно добавить только одно значение на карту, вы можете использовать Collections.singletonMap :
источник
Вы можете использовать
StickyMap
иMapEntry
от Cactoos :источник
Ваш второй подход (инициализация двойной скобки) считается анти-паттерном , поэтому я бы остановился на первом подходе.
Другой простой способ инициализации статической карты - использование этой служебной функции:
Примечание:
Java 9
вы можете использовать Map.ofисточник
Мне не нравится синтаксис статического инициализатора, и я не убежден в анонимных подклассах. Как правило, я согласен со всеми недостатками использования статических инициализаторов и всеми недостатками использования анонимных подклассов, которые были упомянуты в предыдущих ответах. С другой стороны, мне не хватает плюсов, представленных в этих постах. Я предпочитаю использовать статический метод инициализации:
источник
Я не видел подход, который я использую (и который мне понравился), размещенный в каких-либо ответах, поэтому вот он:
Мне не нравится использовать статические инициализаторы, потому что они неуклюжи, и мне не нравятся анонимные классы, потому что они создают новый класс для каждого экземпляра.
вместо этого я предпочитаю инициализацию, которая выглядит так:
к сожалению, эти методы не являются частью стандартной библиотеки Java, поэтому вам нужно будет создать (или использовать) служебную библиотеку, которая определяет следующие методы:
(вы можете использовать «import static», чтобы избежать добавления префикса имени метода)
Я нашел полезным предоставить аналогичные статические методы для других коллекций (list, set, sortedSet, sortedMap и т. Д.)
Это не так хорошо, как инициализация объекта json, но это шаг в этом направлении, что касается читабельности.
источник
Поскольку Java не поддерживает литералы карты, экземпляры карты всегда должны быть явно созданы и заполнены.
К счастью, можно приблизить поведение литералов карты в Java, используя фабричные методы .
Например:
Вывод:
Это намного удобнее, чем создавать и заполнять карту элементом одновременно.
источник
JEP 269 предоставляет некоторые удобные фабричные методы для API коллекций. Методы этой фабрики отсутствуют в текущей версии Java, которая составляет 8, но запланированы для выпуска Java 9.
Ибо
Map
есть два заводских метода:of
аofEntries
. Используяof
, вы можете передавать чередующиеся пары ключ / значение. Например, чтобы создатьMap
подобное{age: 27, major: cs}
:В настоящее время существует десять перегруженных версий для
of
, поэтому вы можете создать карту, содержащую десять пар ключ / значение. Если вам не нравится это ограничение или переменный ключ / значения, вы можете использоватьofEntries
:Оба
of
иofEntries
вернут неизменяемостьMap
, поэтому вы не сможете изменить их элементы после постройки. Вы можете опробовать эти функции, используя JDK 9 Ранний доступ .источник
Ну ... я люблю перечисления;)
источник
Я прочитал ответы и решил написать свой собственный конструктор карт. Не стесняйтесь копировать-вставлять и наслаждаться.
РЕДАКТИРОВАТЬ: В последнее время я продолжаю находить публичный статический метод
of
довольно часто, и мне это нравится. Я добавил его в код и сделал конструктор приватным, переключившись на статический шаблон метода фабрики.РЕДАКТИРОВАТЬ 2: Еще недавно я больше не любил вызывать статический метод
of
, так как он выглядит довольно плохо при использовании статического импорта.mapOf
Вместо этого я переименовал его, чтобы сделать его более подходящим для статического импорта.источник