Как инициализировать HashMap в Java буквальным способом (как литерал)?
Лучший способ: статические фабричные методы (Java 9+)
Начиная с Java 9, в интерфейсе Map появились статические фабричные методы, которые позволяют создавать неизменяемые (immutable) карты буквально. Это самый простой и рекомендуемый способ. Карта будет содержать ровно те пары, которые вы указали, и её нельзя будет изменить после создания.
import java.util.Map;
import java.util.HashMap;
public class Example {
public static void main(String[] args) {
// Создаём неизменяемую карту с 0 элементами
Map<String, String> emptyMap = Map.of();
// С картой из 1 элемента
Map<String, String> singleMap = Map.of("key1", "value1");
// С картой из 2 элементов
Map<String, String> map2 = Map.of("key1", "value1", "key2", "value2");
// До 10 элементов — можно передавать пары ключ-значение последовательно
Map<String, Integer> ages = Map.of(
"Alice", 25,
"Bob", 30,
"Charlie", 35
);
// Если нужно больше 10 элементов, используйте Map.ofEntries
Map<String, Integer> bigMap = Map.ofEntries(
Map.entry("Alice", 25),
Map.entry("Bob", 30),
Map.entry("Charlie", 35),
Map.entry("Diana", 28),
Map.entry("Eve", 32),
Map.entry("Frank", 40),
Map.entry("Grace", 22),
Map.entry("Henry", 27),
Map.entry("Ivy", 33),
Map.entry("Jack", 29),
Map.entry("Kate", 31) // 11-й элемент
);
System.out.println(map2); // {key2=value2, key1=value1}
}
}
Важное замечание: Карты, созданные через Map.of() или Map.ofEntries(), являются неизменяемыми. Попытка вызвать put(), remove() или другие методы изменения приведёт к исключению UnsupportedOperationException.
Как создать изменяемую карту буквально
Если вам нужна изменяемая карта (например, для последующего добавления элементов), используйте комбинацию фабричного метода и конструктора HashMap:
import java.util.Map;
import java.util.HashMap;
public class MutableExample {
public static void main(String[] args) {
// Создаём неизменяемую карту, а затем копируем в HashMap
HashMap<String, String> mutableMap = new HashMap<>(
Map.of("key1", "value1", "key2", "value2")
);
// Теперь можно изменять
mutableMap.put("key3", "value3");
mutableMap.remove("key1");
System.out.println(mutableMap); // {key2=value2, key3=value3}
}
}
Почему это лучше, чем double brace initialization?
Раньше разработчики использовали так называемую "double brace initialization" (двойную инициализацию фигурными скобками):
// ПЛОХОЙ ПРИМЕР — не делайте так!
HashMap<String, String> badMap = new HashMap<>() {{
put("key1", "value1");
put("key2", "value2");
}};
Этот подход создаёт анонимный внутренний класс, что приводит к:
- Утечкам памяти (анонимный класс содержит ссылку на внешний класс)
- Проблемам с сериализацией
- Снижению производительности
- Нечитаемому коду
Методы Map.of() лишены всех этих недостатков.
Для старых версий Java (до 8 включительно)
Если вы застряли на Java 8 (что сейчас редкость), используйте Guava от Google:
// Требуется зависимость: com.google.guava:guava
import com.google.common.collect.ImmutableMap;
Map<String, String> map = ImmutableMap.of(
"key1", "value1",
"key2", "value2"
);
Или через инициализационный блок с последующим копированием в HashMap, как показано выше.
Итог
Лучший способ в современной Java — использовать Map.of() или Map.ofEntries(). Это кратко, читаемо, производительно и безопасно. Если нужна изменяемая карта — просто передайте результат в конструктор HashMap.
Альтернативный ответ: Инициализация с помощью Stream API
Если вы предпочитаете функциональный стиль или хотите динамически формировать карту на лету, можно использовать Stream API. Это особенно полезно, когда пары ключ-значение генерируются из какого-то источника (например, из массива или другой коллекции).
import java.util.*;
import java.util.stream.*;
public class StreamExample {
public static void main(String[] args) {
// Инициализация из массива объектов (чередуются ключ и значение)
Map<String, Integer> mapFromArray = IntStream.range(0, 10)
.boxed()
.collect(Collectors.toMap(
i -> "key" + i,
i -> i * 10
));
// Или из списка пар
List<AbstractMap.SimpleEntry<String, String>> entries = Arrays.asList(
new AbstractMap.SimpleEntry<>("name", "Alice"),
new AbstractMap.SimpleEntry<>("age", "30"),
new AbstractMap.SimpleEntry<>("city", "London")
);
Map<String, String> mapFromEntries = entries.stream()
.collect(Collectors.toMap(
AbstractMap.SimpleEntry::getKey,
AbstractMap.SimpleEntry::getValue
));
System.out.println(mapFromArray); // {key0=0, key1=10, ...}
System.out.println(mapFromEntries); // {name=Alice, age=30, city=London}
}
}
Плюсы: Гибкость, можно добавлять логику обработки (фильтрацию, преобразование) прямо в процессе создания карты.
Минусы: Более многословно, чем Map.of(), и менее читаемо для простых случаев. Подходит, когда количество пар ключ-значение большое или динамическое.