Я подумал, что опущу пару реальных примеров использования интерфейса карты в Java, в основном потому, что все еще существует множество старых ресурсов, которые не используют современную Java. Надеюсь, это поможет!
MapstatesToCapitals = Map.of( "Washington", "Olympia", "Oregon", "Portland", "California", "Sacramento", "Idaho", "Boise", "Nevada", "Carson City", "Arizona", "Phoenix" );
Важно помнить, что карты, созданные таким образом, являются неизменяемыми, и null нельзя использовать в качестве ключа!
Это создает карту следующим образом:
{Nevada=Carson City, California=Sacramento, Washington=Olympia, Idaho=Boise, Oregon=Portland, Arizona=Phoenix}
statesToCapitals.forEach((key, value) -> { System.out.println("The capital of " + key + " is " + value); });
Это привело бы к:
The capital of Washington is Olympia The capital of Idaho is Boise The capital of Oregon is Portland The capital of Arizona is Phoenix The capital of Nevada is Carson City The capital of California is Sacramento
Помимо метода forEach
, доступного непосредственно на карте, который позволяет передавать функцию для применения к ее ключам и/или значениям, вы также можете передавать ее записи и работать с картой . Запись
класс.
Например, вы можете распечатать записи:
capitals.entrySet().stream().forEach(System.out::println);
Это привело бы к:
Washington=Olympia Idaho=Boise Oregon=Portland Arizona=Phoenix Nevada=Carson City California=Sacramento
CollectioncapitalCities = statesToCapitals.values();
Обратите внимание, что в зависимости от используемой реализации карты вы можете получать значения в несортированном или отсортированном порядке.
Так что у вас будет что-то вроде:
[Sacramento, Carson City, Phoenix, Portland, Boise, Olympia]
System.out.println("The capital of Wisconsin is " + statesToCapitals.getOrDefault("Wisconsin", "Don't know"));
Выходы:
The capital of Wisconsin is Don't know
Допустим, вы начали с объекта состояния, который представляет штат США:
class State { public String name() { // ... etc public String capitalCity() { // ... etc }
И если у вас есть коллекция всех штатов США:
CollectionusStates = usStates();
Вы можете создать карту для поиска каждого штата по его названию:
MapnameToState = usStates.stream().collect(Collectors.toMap(State::name, Function.identity()));
Другими словами, теперь вы можете получить Калифорнию с именем В State.get("Калифорния")
и вы получите экземпляр штата
, связанный с Калифорнией.
Предположим, что то же самое, что и выше, но на этот раз вы хотите перейти от штатов к столицам – ключом карты будет значение объекта, его название, например “Калифорния” или “Висконсин”, а значение карты также будет значение объекта, его столицы, например “Сакраменто” или “Мэдисон”.
MapstatesToCapitals = usStates.stream().collect(Collectors.toMap(State::name, State::capitalCity));
Теперь давайте рассмотрим, смог ли государственный объект также вернуть коллекцию всех крупных городов штата:
class State { public String name() { // ... etc public String capitalCity() { // ... etc public ListmajorCities() { // ... etc }
И вы создали штаты для городов
карту, аналогичную приведенной выше, со столицами:
Map> statesToCities = usStates.stream().collect(Collectors.toMap(State::name, State::majorCities));
Разница теперь в том, что у нас есть Карта<Строка, Список<Строка>>
вместо более простого Карта<Строка, строка>
как у нас было раньше. “Значение” карты – это список городов. Например:
ListcaliforniaCities = statesToCities.get("California"); System.out.println(californiaCities); // outputs "[Sacramento, San Francisco, Los Angeles]"
Добавьте значение в список на карте списков
В “старой школе Java” вам нужно было проверить, существует ли ключ на карте, чтобы вы могли выполнить инициализацию списка, если его там не было:
// deprecated way of adding new values Map> statesToCities = statesAndCitiesMap(); if(!statesToCities.containsKey("Montana")) { statesToCities.put("Montana", new ArrayList<>()); } statesToCities.get("Montana").add("Bozeman");
Теперь вы можете использовать computeIfAbsent
вместо get
, чтобы убедиться, что вы начинаете с начального пустого списка, даже если там ничего нет для начала:
statesToCities.computeIfAbsent("Montana", initialValue -> new ArrayList<>()).add("Bozeman");
Вот сценарий реального мира, который постоянно возникает. Что делать, если нам нужна карта для подсчета количества каждого типа чего-либо в коллекции.
Для этого примера давайте предположим, что у нас есть класс телефона с маркой и моделью:
class Phone { public String brand() { // etc ... public String model() { // etc ... }
Примерами могут служить “Apple iPhone 11” или “Google Pixel 4”.
И коллекция телефонов, скажем, все телефоны, которые Amazon предлагает для продажи:
Collectionphones = phonesOnAmazon();
Тогда мы просто пересчитаем их:
MapnumberOfPhonesPerBrand = phones.stream().collect(Collectors.groupingBy(Phone::brand, Collectors.counting()));
Смущен? Коллектор groupingBy
возвращает карту с первым значением, переданным в качестве ключа ( Телефон::бренд
), и вычислением, произведенным переданной функцией в качестве значения. В этом случае мы хотели подсчитать каждый телефон, который мы видели для этой марки, поэтому мы использовали В этом случае мы хотели подсчитать каждый телефон, который мы видели для этой марки, поэтому мы использовали
()
Карта, созданная выше, выглядит так при выводе:
{Google=2, Apple=2}
Чтобы развить предыдущий пример, давайте предположим, что вы хотите узнать, сколько телефонов у Amazon в любой момент времени по бренду. Мы не можем просто сосчитать, сколько там телефонов. Вместо этого в этом примере мы должны использовать метод доступный номер
из класса Телефон
, который сообщает нам, сколько телефонов доступно на Amazon прямо сейчас.
MapnumOfPhonesPerBrand = phones.stream().collect(Collectors.groupingBy(Phone::brand, Collectors.summingInt(Phone::numberAvailable)));
В дополнение к призыву
, есть коллекционеры, называемые суммирование Long
и суммирование Double
, которые могут суммировать значения из методов, возвращающих long или double соответственно.
Допустим, у вас есть список объектов Телефон
и вы хотите создать Карту<Строка, список<Телефон>>
, представляющую список телефонов по маркам. Ключ представляет собой Строку
и является брендом, таким как “Apple” или “Samsung”. Значение карты равно Список<Строка>
и это просто список телефонов, таких как для Apple, это будет [“Apple iPhone 11”, “Apple iPhone 11 Pro” и т. Д.].
Map> phoneListByBrand = phones.stream().collect(Collectors.groupingBy(Phone::brand));
Карта . Класс Entry
имеет ряд собственных статических методов для использования в операциях с картами. Вы можете, например, отсортировать карту перед печатью:
phonesByBrand.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(System.out::println);
Это приведет к:
Apple=[Apple iPhone 11, Apple iPhone 11 Pro] Google=[Google Pixel 4, Google Pixel 4 XL] Samsung=[Samsung Galaxy Note 10, Samsung Galaxy Fold]
Больше ресурсов
Ознакомьтесь с этими ресурсами, если вы хотите узнать больше о современных Java-картах!
Книга: Коузен К. А. (2017). Современные рецепты Java: простые решения сложных проблем в Java 8 и 9.
_ Этот пост первоначально опубликован по адресу code.scottshipp.com
Оригинал: “https://dev.to/scottshipp/java-maps-cheat-sheet-4bb0”