API на Java 8 Streams peek ()

1. Въведение

API на Java Stream ни запознава с мощна алтернатива за обработка на данни.

В този кратък урок ще се съсредоточим върху peek () , често неразбран метод.

2. Бърз пример

Нека си изцапаме ръцете и се опитаме да използваме peek () . Имаме поток от имена и искаме да ги отпечатаме на конзолата.

Тъй като peek () очаква един потребител като единствен аргумент, изглежда добре, така че нека опитаме:

Stream nameStream = Stream.of("Alice", "Bob", "Chuck"); nameStream.peek(System.out::println);

Обаче горният фрагмент не дава изход. За да разберем защо, нека направим кратко опресняване на аспекти на жизнения цикъл на потока.

3. Междинни срещу терминални операции

Спомнете си, че потоците имат три части: източник на данни, нула или повече междинни операции и нула или една терминална операция.

Източникът предоставя елементите на тръбопровода.

Междинните операции получават елементи един по един и ги обработват. Всички междинни операции са мързеливи и в резултат на това никакви операции няма да имат ефект, докато тръбопроводът започне да работи.

Терминалните операции означават края на жизнения цикъл на потока. Най-важното за нашия сценарий е, че те инициират работата в процес .

4. peek () Употреба

Причината peek () да не работи в първия ни пример е, че това е междинна операция и не сме приложили терминална операция към тръбопровода. Друга възможност е да използваме forEach () със същия аргумент, за да получим желаното поведение:

Stream nameStream = Stream.of("Alice", "Bob", "Chuck"); nameStream.forEach(System.out::println);

Страницата на peek () в Javadoc казва: „ Този метод съществува главно за поддържане на отстраняване на грешки, където искате да видите елементите, докато текат след определена точка в конвейер “.

Нека разгледаме този фрагмент от същата страница на Javadoc:

Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList());

Това показва как наблюдаваме елементите, преминали през всяка операция.

На всичкото отгоре, peek () може да бъде полезен в друг сценарий: когато искаме да променим вътрешното състояние на даден елемент . Да приемем например, че искаме да преобразуваме името на всички потребители в малки букви, преди да ги отпечатаме:

Stream userStream = Stream.of(new User("Alice"), new User("Bob"), new User("Chuck")); userStream.peek(u -> u.setName(u.getName().toLowerCase())) .forEach(System.out::println);

Друга възможност е да използваме map () , но peek () е по-удобен, тъй като не искаме да заменим елемента.

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

В този кратък урок видяхме обобщение на жизнения цикъл на потока, за да разберем как работи peek () . Също така видяхме два случая на ежедневна употреба, когато използването на peek () е най-ясната опция.

Както обикновено, примерите са достъпни в GitHub.