- Работа С Картами С Использованием Потоков
- Дальнейшее чтение:
- Объединение двух карт с Java 8
- Java 8 Коллекторы toMap
- Учебник по потоковому API Java 8
- 2. Основная Идея
- 3.1. Входные данные
- 3.2. Получение совпадения
- 3.3. Получение Нескольких Результатов
- 4. Получение значений Карты С помощью потоков
- 5. Заключение
- Читайте ещё по теме:
- Итерация карты в Java с использованием метода entrySet()
- 1. Использование Iterator
- 2. Использование цикла for-each (расширенный оператор for)
- 3. Использование Iterator.forEachRemaining() метод
- Java 8 – Filter a Map examples
- 1. Java 8 – Filter a Map
- 2. Java 8 – Filter a Map #2
- 3. Java 8 – Filter a Map #3 – Predicate
- References
Работа С Картами С Использованием Потоков
В этом уроке мы обсудим некоторые примеры использования потоков Java | для работы с Map s . Стоит отметить, что некоторые из этих упражнений могут быть решены с использованием двунаправленной структуры данных Map , но здесь нас интересует функциональный подход.
Во-первых, мы объясним основную идею, которую мы будем использовать для работы с Maps и Stream s. Затем мы представим несколько различных проблем, связанных с Maps и их конкретными решениями с использованием Stream s.
Дальнейшее чтение:
Объединение двух карт с Java 8
Java 8 Коллекторы toMap
Учебник по потоковому API Java 8
2. Основная Идея
Главное, что следует отметить, это то, что Stream s-это последовательности элементов, которые можно легко получить из Коллекции .
Карты имеют другую структуру, с отображением от ключей к значениям, без последовательности. Однако это не означает, что мы не можем преобразовать структуру Map в различные последовательности, которые затем позволят нам естественным образом работать с API потока.
Давайте рассмотрим способы получения различных Коллекций из Карты , которые затем мы можем превратить в Поток :
Мы можем получить набор пар ключ-значение:
Set> entries = someMap.entrySet();Мы также можем получить набор ключей, связанный с картой :
SetkeySet = someMap.keySet();
Или мы могли бы работать непосредственно с набором значений:
Collectionvalues = someMap.values();
Каждый из них дает нам точку входа для обработки этих коллекций путем получения потоков из них:
Stream> entriesStream = entries.stream(); Stream
3.1. Входные данные
Предположим, у нас есть Карта :
Mapbooks = 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. Мы можем использовать Необязательно , чтобы выразить это:
Давайте предположим для этого примера, что нас интересует любой ключ для книги, соответствующей этому названию:
OptionaloptionalIsbn = 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, которая предоставит начальное значение в потоке в качестве Необязательного объекта.
Давайте рассмотрим случай, в котором название не существует:
OptionaloptionalIsbn = 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”, мы получим более одного результата:
ListisbnCodes = 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”.
Listtitles = 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 .
Читайте ещё по теме:
Итерация карты в Java с использованием метода entrySet()
В этом посте будут обсуждаться различные методы итерации карты в Java с использованием entrySet() метод.
Мы знаем это Map.entrySet() возвращает набор сопоставлений ключ-значение, содержащихся в карте. Итак, мы можем перебрать карту, используя Map.entrySet() , который содержит обе пары ключ-значение. Есть несколько способов сделать это:
1. Использование Iterator
Поскольку карта не расширяет Collection интерфейс, у него нет собственного итератора. Но Map.entrySet() возвращает набор сопоставлений ключ-значение, и поскольку Set расширяет Collection интерфейс, мы можем получить к нему итератор. Теперь мы можем легко обработать каждую пару ключ-значение, используя простой цикл while, как показано ниже:
2. Использование цикла for-each (расширенный оператор for)
Цикл for также имеет другую вариацию, предназначенную для итерации по коллекциям и массивам. Он называется циклом for-each и доступен любому объекту, реализующему цикл. Iterable интерфейс. В качестве Set расширяет Collection интерфейс и Collection расширяет Iterable интерфейс, мы можем использовать цикл for-each для прохода через entrySet. Обратите внимание, что этот подход также вызовет iterator() метод за кадром.
3. Использование Iterator.forEachRemaining() метод
Мы также можем использовать forEachRemaining() метод, который является последним дополнением к Iterator интерфейс в Java 8 и выше. Он выполняет данное действие для каждого оставшегося элемента, пока все элементы не будут обработаны.
Как было показано ранее, мы можем легко получить итератор для множества Map.Entry . Когда у нас есть итератор, мы можем передать ссылку на метод System.out::println или соответствующее лямбда-выражение E -> System.out.println(E) к forEachRemaining() метод, как показано ниже:
Java 8 – Filter a Map examples
Few Java examples to show you how to filter a Map with Java 8 stream API.
Map map = new HashMap<>(); map.put(1, "linode.com"); map.put(2, "heroku.com"); String result = ""; for (Map.Entry entry : map.entrySet()) < if("something".equals(entry.getValue()))< result = entry.getValue(); >>
With Java 8, you can convert a Map.entrySet() into a stream , follow by a filter() and collect() it.
Map map = new HashMap<>(); map.put(1, "linode.com"); map.put(2, "heroku.com"); //Map -> Stream -> Filter -> String String result = map.entrySet().stream() .filter(x -> "something".equals(x.getValue())) .map(x->x.getValue()) .collect(Collectors.joining()); //Map -> Stream -> Filter -> MAP Map collect = map.entrySet().stream() .filter(x -> x.getKey() == 2) .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue())); // or like this Map collect = map.entrySet().stream() .filter(x -> x.getKey() == 3) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
1. Java 8 – Filter a Map
A full example to filter a Map by values and return a String.
package com.mkyong; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; public class TestMapFilter < public static void main(String[] args) < MapHOSTING = new HashMap<>(); HOSTING.put(1, "linode.com"); HOSTING.put(2, "heroku.com"); HOSTING.put(3, "digitalocean.com"); HOSTING.put(4, "aws.amazon.com"); // Before Java 8 String result = ""; for (Map.Entry entry : HOSTING.entrySet()) < if ("aws.amazon.com".equals(entry.getValue())) < result = entry.getValue(); >> System.out.println("Before Java 8 : " + result); //Map -> Stream -> Filter -> String result = HOSTING.entrySet().stream() .filter(map -> "aws.amazon.com".equals(map.getValue())) .map(map -> map.getValue()) .collect(Collectors.joining()); System.out.println("With Java 8 : " + result); // filter more values result = HOSTING.entrySet().stream() .filter(x -> < if (!x.getValue().contains("amazon") && !x.getValue().contains("digital")) < return true; >return false; >) .map(map -> map.getValue()) .collect(Collectors.joining(",")); System.out.println("With Java 8 : " + result); > >
Before Java 8 : aws.amazon.com With Java 8 : aws.amazon.com With Java 8 : linode.com,heroku.com
2. Java 8 – Filter a Map #2
Yet another example to filter a Map by key, but this time will return a Map
package com.mkyong; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; public class TestMapFilter2 < public static void main(String[] args) < MapHOSTING = new HashMap<>(); HOSTING.put(1, "linode.com"); HOSTING.put(2, "heroku.com"); HOSTING.put(3, "digitalocean.com"); HOSTING.put(4, "aws.amazon.com"); //Map -> Stream -> Filter -> Map Map collect = HOSTING.entrySet().stream() .filter(map -> map.getKey() == 2) .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue())); System.out.println(collect); //output : Map collect2 = HOSTING.entrySet().stream() .filter(map -> map.getKey() > >
3. Java 8 – Filter a Map #3 – Predicate
This time, try the new Java 8 Predicate
package com.mkyong; import java.util.HashMap; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; public class TestMapFilter3 < // Generic Map filterbyvalue, with predicate public static Map filterByValue(Map map, Predicate predicate) < return map.entrySet() .stream() .filter(x ->predicate.test(x.getValue())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); > public static void main(String[] args) < MapHOSTING = new HashMap<>(); HOSTING.put(1, "linode.com"); HOSTING.put(2, "heroku.com"); HOSTING.put(3, "digitalocean.com"); HOSTING.put(4, "aws.amazon.com"); HOSTING.put(5, "aws2.amazon.com"); // Map filteredMap = filterByValue(HOSTING, x -> x.contains("linode")); System.out.println(filteredMap); // Map filteredMap2 = filterByValue(HOSTING, x -> (x.contains("aws") || x.contains("linode"))); System.out.println(filteredMap2); // Map filteredMap3 = filterByValue(HOSTING, x -> (x.contains("aws") && !x.contains("aws2"))); System.out.println(filteredMap3); // Map filteredMap4 = filterByValue(HOSTING, x -> (x.length() >