User Джон Дориан
Джон Дориан
37 уровень

Хватит писать циклы! Топ-10 лучших методов для работы с коллекциями из Java 8

Статья из группы Random
Что такое коллекции и для чего они нужны, думаю, ученикам JavaRush объяснять не надо. Однако после выхода 8-ой версии многие элементарные операции, на которые раньше уходило 6-7 строчек кода, были упрощены до минимума. Без лишних предисловий — топ-10 лучших методов Java8 Collections Framework, которые сэкономят вам кучу времени и места! Хватит писать циклы! Топ-10 лучших методов для работы с коллекциями из Java 8 - 1Всем привет, друзья! Привычка, как известно, вторая натура. И привыкнув писать for (int i = 0; i <......) переучиваться совсем не хочется (тем более, что конструкция эта довольно проста и понятна). Однако, внутри циклов мы часто повторяем одни и те же элементарные операции, от повторения которых очень хотелось бы избавиться. С выходом Java8 Oracle решили помочь нам с этим. Ниже — 10 лучших методов коллекций, которые сэкономят вам кучу времени и кода

1. Iterable.forEach(Consumer<? super T> action)

Название говорит само за себя. Перебирает переданную коллекцию, и выполняет лямбда-выражение action для каждого ее элемента.

List <Integer> numbers = new ArrayList<>(Arrays.asList(1,2,3,4,5,6,7));
numbers.forEach(s -> System.out.print(s + " "));

1 2 3 4 5 6 7 

2. Collection.removeIf(Predicate<? super E> filter)

Тоже ничего сложного. Метод перебирает коллекцию, и удаляет те элементы, которые соответствуют filter.

List <Integer> numbers = new ArrayList<>(Arrays.asList(1,2,3,4,5,6,7));
numbers.removeIf(s -> s > 5);
 numbers.forEach(s -> System.out.print(s + " "));
В одну строку удаляем из списка все числа больше 5.

3. Map.forEach(BiConsumer<? super K, ? super V> action)

Метод forEach работает не только для классов, реализующих интерфейс Collection, но и для Map.

Map <String, String> books = new HashMap<>();
books.put("Война и мир", "Лев Толстой");
books.put("Преступление и наказание", "Федор Достоевский");
books.put("Философия Java", "Брюс Эккель");
books.put("Братья Карамазовы", "Федор Достоевский");
books.put("Властелин Колец", "Джон Толкин");
books.forEach((a,b) -> System.out.println("Название книги: " + a + ". Автор: " + b));

Название книги: Братья Карамазовы. Автор: Федор Достоевский
Название книги: Философия Java. Автор: Брюс Эккель
Название книги: Преступление и наказание. Автор: Федор Достоевский
Название книги: Война и мир. Автор: Лев Толстой
Название книги: Властелин Колец. Автор: Джон Толкин

4. Map.compute(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction)

Выглядит чуть более устрашающе, но на деле прост, как и все предыдущие. Для указанного ключа key этот метод устанавливает в качестве value результат выполнения функции remappingFunction. Например:

Map <String, String> books = new HashMap<>();
books.put("Война и мир", "Лев Толстой");
books.put("Преступление и наказание", "Федор Достоевский");
books.put("Философия Java", "Брюс Эккель");
books.put("Братья Карамазовы", "Федор Достоевский");
books.put("Властелин Колец", "Джон Толкин");
books.forEach((a,b) -> System.out.println("Название книги: " + a + ". Автор: " + b));

books.compute("Философия Java", (a,b) -> b+", крутой чувак");
System.out.println("_______________________");
books.forEach((a,b) -> System.out.println("Название книги: " + a + ". Автор: " + b));

Название книги: Братья Карамазовы. Автор: Федор Достоевский
Название книги: Философия Java. Автор: Брюс Эккель
Название книги: Преступление и наказание. Автор: Федор Достоевский
Название книги: Война и мир. Автор: Лев Толстой
Название книги: Властелин Колец. Автор: Джон Толкин
_______________________
Название книги: Братья Карамазовы. Автор: Федор Достоевский
Название книги: Философия Java. Автор: Брюс Эккель, крутой чувак
Название книги: Преступление и наказание. Автор: Федор Достоевский
Название книги: Война и мир. Автор: Лев Толстой
Название книги: Властелин Колец. Автор: Джон Толкин
Автор "Философии Java" определенно крут!:)

5. Map.computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

Метод добавит новый элемент в Map, но только в том случае, если элемент с таким ключом там отсутствует. В качестве value ему будет присвоен результат выполнения функции mappingFunction. Если же элемент с таким ключом уже есть — он не будет перезаписан, а останется на месте. Вернемся к нашим книгам и испробуем новый метод:

Map <String, String> books = new HashMap<>();
books.put("Война и мир", "Лев Толстой");
books.put("Преступление и наказание", "Федор Достоевский");
books.put("Философия Java", "Брюс Эккель");
books.put("Братья Карамазовы", "Федор Достоевский");
books.put("Властелин Колец", "Джон Толкин");

books.computeIfAbsent("Гарри Поттер и узник Азкабана", b -> getHarryPotterAuthor());
books.forEach((a,b) -> System.out.println("Название книги: " + a + ". Автор: " + b));
Наша функция mappingFunction:

public static String getHarryPotterAuthor() {
        return "Джоан Роулинг";
    }
А вот и новая книга:

Название книги: Братья Карамазовы. Автор: Федор Достоевский
Название книги: Философия Java. Автор: Брюс Эккель
Название книги: Преступление и наказание. Автор: Федор Достоевский
Название книги: Война и мир. Автор: Лев Толстой
Название книги: Гарри Поттер и узник Азкабана. Автор: Джоан Роулинг
Название книги: Властелин Колец. Автор: Джон Толкин

6. Map.computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)

Тот же принцип, что и у Map.compute(), но все вычисления будут выполнены только в случае, если элемент с ключом key уже существует.

Map <String, String> books = new HashMap<>();
books.put("Война и мир", "Лев Толстой");
books.put("Преступление и наказание", "Федор Достоевский");
books.put("Философия Java", "Брюс Эккель");
books.put("Братья Карамазовы", "Федор Достоевский");
books.put("Властелин Колец", "Джон Толкин");

books.computeIfPresent("Евгений Онегин", (a,b) -> b="Александр Пушкин");
System.out.println("_________________");
books.forEach((a,b) -> System.out.println("Название книги: " + a + ". Автор: " + b));
books.computeIfPresent("Братья Карамазовы", (a,b) -> b="Александр Пушкин");
System.out.println("_________________");
books.forEach((a,b) -> System.out.println("Название книги: " + a + ". Автор: " + b));
При первом вызову функции никаких изменений не произошло, потому что книги с названием "Евгений Онегин" в нашей Map нет. А вот во второй раз программа изменила автора для книги "Братья Карамазовы" на "Александр Пушкин". Вывод:

_________________
Название книги: Братья Карамазовы. Автор: Федор Достоевский
Название книги: Философия Java. Автор: Брюс Эккель
Название книги: Преступление и наказание. Автор: Федор Достоевский
Название книги: Война и мир. Автор: Лев Толстой
Название книги: Властелин Колец. Автор: Джон Толкин
_________________
Название книги: Братья Карамазовы. Автор: Александр Пушкин
Название книги: Философия Java. Автор: Брюс Эккель
Название книги: Преступление и наказание. Автор: Федор Достоевский
Название книги: Война и мир. Автор: Лев Толстой
Название книги: Властелин Колец. Автор: Джон Толкин

7. Map.getOrDefault(Object key, V defaultValue)

Возвращает значение, соответствующее ключу key. Если такой ключ не существует — возвращает значение по умолчанию.

Map <String, String> books = new HashMap<>();
books.put("Война и мир", "Лев Толстой");
books.put("Преступление и наказание", "Федор Достоевский");
books.put("Философия Java", "Брюс Эккель");
books.put("Братья Карамазовы", "Федор Достоевский");
books.put("Властелин Колец", "Джон Толкин");

String igor = books.getOrDefault("Слово о полку Игореве", "Неизвестный автор");
System.out.println(igor);
Очень удобно:

Неизвестный автор

8. Map.merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)

Я даже не стал пытаться посчитать, сколько строк кода вам сэкономит этот метод.
  • Если в вашей Map ключ key не существует, или value для этого ключа равно null — метод добавляет в Map переданную пару key-value.
  • Если ключ Key существует и его value != null — метод меняет его value на результат выполнения переданной функции remappingFunction.
  • Если remappingFunction возвращает null - key удаляется из коллекции.

Map <String, String> books = new HashMap<>();
books.put("Война и мир", "Лев Толстой");
books.put("Преступление и наказание", "Федор Достоевский");
books.put("Философия Java", "Брюс Эккель");
books.put("Братья Карамазовы", "Федор Достоевский");
books.put("Властелин Колец", "Джон Толкин");

books.merge("Философия Java", "Брюс Эккель", (a, b) -> b +  " и кто-то там еще");
books.forEach((a,b) -> System.out.println("Название:" + a + ". Автор: " + b));
Вывод:

Название:Братья Карамазовы. Автор: Федор Достоевский
Название:Философия Java. Автор: Брюс Эккель и кто-то там еще
Название:Преступление и наказание. Автор: Федор Достоевский
Название:Война и мир. Автор: Лев Толстой
Название:Властелин Колец. Автор: Джон Толкин
*извини, Брюс*

9. Map.putIfAbsent(K key, V value)

Раньше чтобы добавить пару в Map, если ее там нет, необходимо было делать следующее:

Map <String, String> map = new HashMap<>();
if (map.get("Властелин Колец") == null)
    map.put("Властелин Колец", "Джон Толкин");
Теперь все стало куда проще:

Map<String, String> map = new HashMap<>();
map.putIfAbsent("Властелин Колец", "Джон Толкин");

10. Map.replace и Map.replaceAll()

Последние по списку, но не по значимости. Map.replace(K key, V newValue — заменяет значение ключа key на newValue, если такой ключ существует. Если нет — ничего не происходит. Map.replace(K key, V oldValue, V newValue) — делает то же самое, но только если текущее значение key равно oldValue. Map.replaceAll(BiFunction<? super K, ? super V, ? extends V> function) — заменяет все значения value на результат выполнения функции function. Например:

Map <String, String> books = new HashMap<>();
books.put("Война и мир", "Лев Толстой");
books.put("Преступление и наказание", "Федор Достоевский");
books.put("Философия Java", "Брюс Эккель");
books.put("Братья Карамазовы", "Федор Достоевский");
books.put("Властелин Колец", "Джон Толкин");

books.replace("Братья Карамазовы", "Брюс Эккель", "Джон Толкин");
books.forEach((a,b) -> System.out.println("Название:" + a + ". Автор: " + b));

Название:Братья Карамазовы. Автор: Федор Достоевский
Название:Философия Java. Автор: Брюс Эккель
Название:Преступление и наказание. Автор: Федор Достоевский
Название:Война и мир. Автор: Лев Толстой
Название:Властелин Колец. Автор: Джон Толкин
Не сработало! Текущее значение ключа "Братья Карамазовы" — "Федор Достоевский", а не "Брюс Эккель", поэтому ничего не изменилось.

Map <String, String> books = new HashMap<>();
books.put("Война и мир", "Лев Толстой");
books.put("Преступление и наказание", "Федор Достоевский");
books.put("Философия Java", "Брюс Эккель");
books.put("Братья Карамазовы", "Федор Достоевский");
books.put("Властелин Колец", "Джон Толкин");

books.replaceAll((a,b) -> getCoolWriter());
books.forEach((a,b) -> System.out.println("Название:" + a + ". Автор: " + b));

public static String getCoolWriter() {
        return "Крутой писатель";
    }

Название:Братья Карамазовы. Автор: Крутой писатель
Название:Философия Java. Автор: Крутой писатель
Название:Преступление и наказание. Автор: Крутой писатель
Название:Война и мир. Автор: Крутой писатель
Название:Властелин Колец. Автор: Крутой писатель
Легко изменили значения для всей Map безо всяких сложных конструкций! Хватит писать циклы! Топ-10 лучших методов для работы с коллекциями из Java 8 - 2P.S. Привыкать к новому всегда непросто, но эти изменения действительно хороши. Во всяком случае, некоторые куски моего кода теперь определенно меньше похожи на спагетти, чем раньше:) Если вам понравилась статья, и вы хотели бы увидеть новые - не забудьте поддержать автора в конкурсе, нажав "Нравится", а лучше - "Очень нравится" :) Успехов в обучении!
Комментарии (37)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
wan-derer.ru Уровень 40 Москва Россия
14 июня 2021
8. Map.merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) ... Если в вашей Map ключ key не существует, или value для этого ключа равно null — метод добавляет в Map переданную пару key-value. =========== М... Чё-та нет! Даёт NPE! Вот код метода:

@Override
public V merge(K key, V value,
               BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
    if (value == null)
        throw new NullPointerException();
........
}
Егор Уровень 14 Днепр Украина
2 апреля 2021
Можно ли через copy.forEach(перебор копии коллекции Map) удалить(remove) записи из Map? (если да, то каким способом?)
Alexandr Grishin Уровень 27 Саранск Россия
20 марта 2021
Могу еще посоветовать статью про Map.merge(): Один метод, чтобы управлять всем остальными: Автор по полочкам разложил недостатки каждого метода работы с Map. И показывает merge() как универсальную замену. mapmerge-one-method-to-rule-them-all Немного корявый перевод: mapmerge-metod-chtoby-upravlyat-vsemi-ostalnym
Anonymous #2481357 Уровень 37
24 декабря 2020
теперь я понял зачем google изобрели go.
ShyBerserk Уровень 14 Москва
17 ноября 2020
По поводу 10, для тех, кто не сперва не понял. Лучше поменять формулировку, а то может показаться, будто мы меняем сам ключ. Map.replace(K key, V newValue); -- заменяет значение (value), соответствующее ключу key на newValue, если такой ключ существует. Если нет — ничего не происходит. Map.replace(K key, V oldValue, V newValue); -- заменяет значение (value), соответствующе ключу key на newValue, но только если текущее значение, соответствующее ключу key равно oldValue.
Алина Уровень 13 Москва Россия
10 ноября 2020
это самое лучшее, что мне попалось по коллекциям .... наткнулась случайно в комментариях когда решала задачу .... Автору низкий поклон )))))))))))))))))))))))))))))🥳🥳🥳🥳
🦔 Виктор Уровень 20 Москва Россия Expert
30 октября 2020
Самая откровенная для меня статья за весь курс. Случайно наткнулся на неё в комментариях под конец 8 уровня (коллекции и множества). Двоякие впечатления: с одной стороны прочитал бы я эту статью заранее, то, наверное, раза в 2 быстрее прошёл 8 уровень, с другой стороны, лучше разобрался в теме, т. к. самостоятельно реализовывал аналоги этих методов. Спасибо за подборку, отличные методы, оптимизирующие рутинную работу с коллекциями. Ещё и на лямбды глаза открыли, низкий поклон! В закладки! -- tlgrm: LetsCodeIt / SefoNotasi
Oleksandr Bahno Уровень 22 Днепр Украина
17 октября 2020
подскажите, хочу четко понимать что значит выражение например (Consumer<? super T> action) . По какому запросу гуглить? Что читать?
Andrei Уровень 36 Санкт-Петербург
8 октября 2020
Большое спасибо за статью. Разобрался, хоть и не сразу доходило
max Уровень 8
15 августа 2020
Про спагетти это Вы в точку! Круто, что вы стараетесь за-мотивировать по-умному тех, у кого проблемы с само-мотивацией и / или не самое грамотное представление о привычках. Это к тому - что то, что научился делать раз - становиться заразным. Жизнь. Классный у вас портал-) джрш Хз что выйдет - но учиться интересно!