Рубрики
Без рубрики

Работа С Картами С Использованием Потоков

Узнайте, как объединить карты Java и потоки

Автор оригинала: baeldung.

1. введение

В этом уроке мы обсудим некоторые примеры использования потоков Java | для работы с Map s . Стоит отметить, что некоторые из этих упражнений могут быть решены с использованием двунаправленной структуры данных Map , но здесь нас интересует функциональный подход.

Во-первых, мы объясним основную идею, которую мы будем использовать для работы с Maps и Stream s. Затем мы представим несколько различных проблем, связанных с Maps и их конкретными решениями с использованием Stream s.

Дальнейшее чтение:

Объединение двух карт с Java 8

Java 8 Коллекторы toMap

Учебник по потоковому API Java 8

2. Основная Идея

Главное, что следует отметить, это то, что Stream s-это последовательности элементов, которые можно легко получить из Коллекции .

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

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

Map someMap = new HashMap<>();

Мы можем получить набор пар ключ-значение:

Set> entries = someMap.entrySet();

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

Set keySet = someMap.keySet();

Или мы могли бы работать непосредственно с набором значений:

Collection values = someMap.values();

Каждый из них дает нам точку входа для обработки этих коллекций путем получения потоков из них:

Stream> entriesStream = entries.stream();
Stream valuesStream = values.stream();
Stream keysStream = keySet.stream();

3. Получение ключей Карты С помощью Потоков

3.1. Входные данные

Предположим, у нас есть Карта :

Map books = new HashMap<>();
books.put(
"978-0201633610", "Design patterns : elements of reusable object-oriented software");
books.put(
  "978-1617291999", "Java 8 in Action: Lambdas, Streams, and functional-style programming");
books.put("978-0134685991", "Effective Java");

Мы заинтересованы в том, чтобы найти ISBN для книги под названием “Эффективная Java.”

3.2. Получение совпадения

Поскольку название книги не может существовать в нашей карте , мы хотим иметь возможность указать, что для нее нет связанного ISBN. Мы можем использовать Необязательно , чтобы выразить это:

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

Optional optionalIsbn = books.entrySet().stream()
  .filter(e -> "Effective Java".equals(e.getValue()))
  .map(Map.Entry::getKey)
  .findFirst();

assertEquals("978-0134685991", optionalIsbn.get());

Давайте проанализируем код. Во-первых, мы получаем entrySet из Map , как мы видели ранее.

Мы хотим рассматривать только записи с “Эффективной Java” в качестве заголовка, поэтому первой промежуточной операцией будет фильтр .

Нас интересует не вся запись Map , а ключ каждой записи. Таким образом, следующая цепная промежуточная операция делает именно это: это операция map , которая создаст новый поток в качестве вывода, который будет содержать только ключи для записей, соответствующих названию, которое мы искали.

Поскольку нам нужен только один результат, мы можем применить операцию findFirst() terminal, которая предоставит начальное значение в потоке в качестве Необязательного объекта.

Давайте рассмотрим случай, в котором название не существует:

Optional optionalIsbn = books.entrySet().stream()
  .filter(e -> "Non Existent Title".equals(e.getValue()))
  .map(Map.Entry::getKey).findFirst();

assertEquals(false, optionalIsbn.isPresent());

3.3. Получение Нескольких Результатов

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

Чтобы получить несколько результатов, давайте добавим следующую книгу в нашу Карту :

books.put("978-0321356680", "Effective Java: Second Edition");

Так что теперь, если мы будем искать все книги, которые начинаются с “Эффективной Java”, мы получим более одного результата:

List isbnCodes = books.entrySet().stream()
  .filter(e -> e.getValue().startsWith("Effective Java"))
  .map(Map.Entry::getKey)
  .collect(Collectors.toList());

assertTrue(isbnCodes.contains("978-0321356680"));
assertTrue(isbnCodes.contains("978-0134685991"));

Что мы сделали в этом случае, так это заменили условие фильтра, чтобы проверить, начинается ли значение в Map с “Эффективной Java” вместо сравнения для String равенства.

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

4. Получение значений Карты С помощью потоков

Теперь давайте сосредоточимся на другой проблеме с картами. Вместо получения ISBNs на основе titles , мы попытаемся получить titles на основе ISBNS.

Давайте использовать исходную карту . Мы хотим найти названия с ISBN, начинающимся с “978-0”.

List titles = books.entrySet().stream()
  .filter(e -> e.getKey().startsWith("978-0"))
  .map(Map.Entry::getValue)
  .collect(Collectors.toList());

assertEquals(2, titles.size());
assertTrue(titles.contains(
  "Design patterns : elements of reusable object-oriented software"));
assertTrue(titles.contains("Effective Java"));

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

Также, как и раньше, если бы мы хотели вернуть только первое совпадение, то после метода map мы могли бы вызвать метод findFirst() вместо сбора всех результатов в List .

5. Заключение

В этой статье мы продемонстрировали, как обрабатывать Карту функциональным способом .

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

Конечно, все примеры в этой статье можно найти в проекте GitHub .