В ежедневном кодировании мы сталкиваемся с различными ситуациями, когда нам нужно получить список из карты для удовлетворения различных требований. В этом посте вы узнаете, как преобразовать заданный список в карту Java.
1. Введение
Интерфейс списка — дочерний интерфейс коллекции. Он упорядочен, индексирован и допускает дублирование элементов.Существуют различные классы реализации для интерфейса списка, такие как ArrayList, LinkedList и т. д.
Интерфейс Map представляет группу объектов как пару ключ-значение. Ключи Map всегда уникальны, то есть дублирующиеся ключи не допускаются в Map, но мы можем иметь дублирующиеся значения. Существуют различные классы реализации для Map, такие как HashMap, LinkedHashMap,TreeMap и т. д.
2. Различные способы преобразования списка в карту
Давайте теперь рассмотрим различные способы преобразования списка в карту.
У нас есть запись Employee с полями id и name. Для демонстрации мы создаем два списка,
- «uniqueEmployeeList» содержит данные о сотрудниках, имеющие уникальный идентификатор для всех сотрудников.
- «duplicateEmployeeList» содержит данные о сотрудниках, имеющие дублирующиеся идентификаторы для некоторых сотрудников.
record Employee(int id, String name) {}
// Creating unique employee data listList<Employee> uniqueEmployeeList = new ArrayList<>();// Creating duplicate employee data listList<Employee> duplicateEmployeeList = new ArrayList<>();//Add records to both lists
2.1 Использование цикла forEach()
Давайте используем цикл forEach() для перебора списка сотрудников и добавим соответствующий ключ и значение в карту с помощью метода put().
Map<Integer, Employee> employeeMap = new HashMap<>();for(Employee employee: uniqueEmployeeList) {employeeMap.put(employee.id(), employee);}
Вместо уникального списка сотрудников, если мы используем список, содержащий дубликаты сотрудников, то старое значение будет заменено новым значением для этого ключа в созданной карте. Чтобы избежать этого, мы можем разместить ConcurrentList для хранения всех записей сотрудников для данного ключа.
Map<Integer, List> employeeMapWithListValue = new HashMap<>();for(Employee employee: duplicateEmployeeList) {if(employeeMapWithListValue.containsKey(employee.id())) {employeeMapWithListValue.get(employee.id()).add(employee);} else {ArrayList<Employee> list = new ArrayList<>();list.add(employee);employeeMapWithListValue.put(employee.id(), list);}}
2.2 Использование Collectors.toMap()
Начиная с версии Java 1.8, мы можем использовать потоки и коллекторы для преобразования списка в карту с помощью метода toMap().
Map<Integer, Employee> employeeMap = uniqueEmployeeList.stream().collect(Collectors.toMap(Employee::id, Function.identity()));
Если мы используем дублирующийся список сотрудников, то метод toMap() вызывает IllegalStateException. Чтобы решить эту проблему, нам нужно использовать другой вариант метода toMap(), который принимает третий аргумент в качестве функции слияния, которая используется для разрешения коллизий между значениями, связанными с одним и тем же ключом.
Map<Integer, List<Employee>> employeeMapWithListValue = duplicateEmployeeList.stream().collect(Collectors.toMap(item -> item.id(),item -> new ArrayList<>(Arrays.asList(item)),(l1, l2) -> {l1.addAll(l2);return l1;}));
2.3 Использование Collectors.groupingBy()
Мы можем использовать метод groupingBy(), который лучше всего использовать, когда в списке есть повторяющиеся элементы и мы хотим создать карту с уникальными ключами и всеми значениями, связанными с повторяющимся ключом в списке, т. е. если мы хотим сохранить все значения, связанные с одним и тем же ключом в карте, то мы используем этот метод.
Map<Integer, List<Employee>> employeeMapWithListValue = duplicateEmployeeList.stream().collect(Collectors.groupingBy(Employee::id,Collectors.mapping(Function.identity(), Collectors.toList())));
Обратите внимание на выходные данные программы: все значения, связанные с дубликатами идентификаторов сотрудников «1» и «2», сохраняются в списке, и программа возвращает карту с ключом в виде целого числа и значением в виде списка <Сотрудник>.
2.4. MapUtils.populateMap() из коллекции Apache Commons
Для создания карты из списка мы можем использовать класс MapUtils, представленный в библиотеке Apache Commons Collections.
Map<Integer, Employee> employeeMap = new HashMap<>();MapUtils.populateMap(employeeMap, uniqueEmployeeList, Employee::id);
В случае наличия дублирующихся значений в списке мы можем использовать тип Multimap, который автоматически сохраняет несколько значений в списке, сопоставленных одному ключу.
Multimap employeeMultiMap = ArrayListMultimap.create();duplicateEmployeeList.stream().forEach(e -> employeeMultiMap.put(e.id(), e));
2.5 Использование Maps.uniqueIndex() Guava
Мы также можем использовать метод uniqueIndex() класса Maps библиотеки Guava для создания карты из списка.
Map<Integer, Employee> employeeMap = Maps.uniqueIndex(uniqueEmployeeList, Employee::id);
Как и метод Collectors.toMap(), указанный выше, если список содержит дублирующиеся записи, то метод uniqueIndex() также вызывает исключение IllegalStateException.
Чтобы решить эту проблему, мы можем использовать метод MultiMaps.index() библиотеки Guava, который делает то же самое, но возвращает Multimap(который может содержать произвольное количество значений на ключ), как и метод Collectors.groupingBy().
ImmutableListMultimap<Integer, Employee> employeeMap = Multimaps.index(duplicateEmployeeList, Employee::id);
3. Заключение
Мы изучили различные способы, с помощью которых мы можем преобразовать список в карту в Java. Мы рассмотрели оба сценария, когда список содержит уникальные элементы, а также когда список содержит дублирующиеся элементы.