1. Обзор
В этом учебнике мы посмотрим на основные особенности Протонпак которая является библиотекой, которая расширяет стандартный Поток API добавив некоторые бесплатные функции.
Обратитесь к это написать здесь чтобы открыть для себя основы Java Поток API.
2. Зависимость от Maven
Чтобы использовать библиотеку Protonpack, мы должны добавить зависимость в нашем пом.xml файл:
com.codepoetics protonpack 1.15
Проверьте последнюю версию на Мавен Центральный .
3. СтримУтилс
Это основной класс, который расширяет стандартные возможности Java Поток API.
Все методы, обсуждаемые здесь, промежуточные операции , что означает, что они изменяют Поток но не вызывает его обработки.
3.1. takeWhile () и takeUntil()
takeWhile () берет значения из исходных потоков до тех пор, пока они отвечают поставленным :
StreamstreamOfInt = Stream .iterate(1, i -> i + 1); List result = StreamUtils .takeWhile(streamOfInt, i -> i < 5) .collect(Collectors.toList()); assertThat(result).contains(1, 2, 3, 4);
И наоборот, takeUntil () принимает значения до тех пор, пока значение не соответствует поставленным а затем останавливается:
StreamstreamOfInt = Stream .iterate(1, i -> i + 1); List result = StreamUtils .takeUntil(streamOfInt, i -> i >= 5) .collect(Collectors.toList()); assertThat(result).containsExactly(1, 2, 3, 4);
В Java 9 далее, takeWhile () является частью стандартного Поток API .
3.2.zip()
zip () принимает два или три потока в качестве ввода и функции комбайна. Метод берет значение из одного и того же положения каждого потока и передает его комбайну .
Он делает это до тех пор, пока у одного из потоков не иссякнут значения:
String[] clubs = {"Juventus", "Barcelona", "Liverpool", "PSG"}; String[] players = {"Ronaldo", "Messi", "Salah"}; SetzippedFrom2Sources = StreamUtils .zip(stream(clubs), stream(players), (club, player) -> club + " " + player) .collect(Collectors.toSet()); assertThat(zippedFrom2Sources) .contains("Juventus Ronaldo", "Barcelona Messi", "Liverpool Salah");
Аналогичным образом, перегруженный zip () что занимает три источника потока:
String[] leagues = { "Serie A", "La Liga", "Premier League" }; SetzippedFrom3Sources = StreamUtils .zip(stream(clubs), stream(players), stream(leagues), (club, player, league) -> club + " " + player + " " + league) .collect(Collectors.toSet()); assertThat(zippedFrom3Sources).contains( "Juventus Ronaldo Serie A", "Barcelona Messi La Liga", "Liverpool Salah Premier League");
3.3. zipWithIndex()
zipWithIndex () принимает значения и застегнул каждое значение своим индексом, чтобы создать поток индексных значений:
StreamstreamOfClubs = Stream .of("Juventus", "Barcelona", "Liverpool"); Set > zipsWithIndex = StreamUtils .zipWithIndex(streamOfClubs) .collect(Collectors.toSet()); assertThat(zipsWithIndex) .contains(Indexed.index(0, "Juventus"), Indexed.index(1, "Barcelona"), Indexed.index(2, "Liverpool"));
3.4. слияние ()
слияние () работает с несколькими потоками источников и комбайном. Это принимает значение одной и той же позиции индекса из каждого потока источника и передает его комбайну .
Метод работает, взяв 1 значение из одного и того же индекса из каждого потока подряд, начиная с семена ценность.
Затем значение передается комбайну, и полученное комбинированное значение подается обратно комбайну для создания следующего значения:
StreamstreamOfClubs = Stream .of("Juventus", "Barcelona", "Liverpool", "PSG"); Stream streamOfPlayers = Stream .of("Ronaldo", "Messi", "Salah"); Stream streamOfLeagues = Stream .of("Serie A", "La Liga", "Premier League"); Set merged = StreamUtils.merge( () -> "", (valOne, valTwo) -> valOne + " " + valTwo, streamOfClubs, streamOfPlayers, streamOfLeagues) .collect(Collectors.toSet()); assertThat(merged) .contains("Juventus Ronaldo Serie A", "Barcelona Messi La Liga", "Liverpool Salah Premier League", "PSG");
3.5. слияниеToList()
слияниеToList () принимает несколько потоков в качестве ввода. Это объединяет значение одного и того же индекса из каждого потока в Список :
StreamstreamOfClubs = Stream .of("Juventus", "Barcelona", "PSG"); Stream streamOfPlayers = Stream .of("Ronaldo", "Messi"); Stream > mergedStreamOfList = StreamUtils .mergeToList(streamOfClubs, streamOfPlayers); List
> mergedListOfList = mergedStreamOfList .collect(Collectors.toList()); assertThat(mergedListOfList.get(0)) .containsExactly("Juventus", "Ronaldo"); assertThat(mergedListOfList.get(1)) .containsExactly("Barcelona", "Messi"); assertThat(mergedListOfList.get(2)) .containsExactly("PSG");
3.6. переплетение ()
переплетение () создает альтернативные значения, взятые из нескольких потоков с помощью селектор .
Метод дает набор, содержащий одно значение от каждого потока к селектор , и селектор выберет одно значение.
Затем выбранное значение будет удалено из набора и заменено следующим значением, из которого возникло выбранное значение. Эта итерация продолжается до тех пор, пока у всех источников не выходят значения.
В следующем примере используется переплетение () создавать переменные значения с круговой стратегия:
StreamstreamOfClubs = Stream .of("Juventus", "Barcelona", "Liverpool"); Stream streamOfPlayers = Stream .of("Ronaldo", "Messi"); Stream streamOfLeagues = Stream .of("Serie A", "La Liga"); List interleavedList = StreamUtils .interleave(Selectors.roundRobin(), streamOfClubs, streamOfPlayers, streamOfLeagues) .collect(Collectors.toList()); assertThat(interleavedList) .hasSize(7) .containsExactly("Juventus", "Ronaldo", "Serie A", "Barcelona", "Messi", "La Liga", "Liverpool");
Имейте в виду, что выше код для учебника цели, потому что круговой селектор предоставляется библиотекой в качестве Селекторы.круглыйРобин () .
3.7. пропуститьUntil () и пропуститьWhile ()
skipUntil () пропускает значения до тех пор, пока значение не соответствует :
Integer[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; List skippedUntilGreaterThan5 = StreamUtils .skipUntil(stream(numbers), i -> i > 5) .collect(Collectors.toList()); assertThat(skippedUntilGreaterThan5).containsExactly(6, 7, 8, 9, 10);
В отличие от этого, skipWhile () пропускает значения, в то время как значения соответствуют :
Integer[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; List skippedWhileLessThanEquals5 = StreamUtils .skipWhile(stream(numbers), i -> i <= 5 || ) .collect(Collectors.toList()); assertThat(skippedWhileLessThanEquals5).containsExactly(6, 7, 8, 9, 10);
Одна важная вещь в skipWhile () является то, что он будет продолжать потоковое после того, как он нашел первое значение, которое не соответствует условию:
List skippedWhileGreaterThan5 = StreamUtils .skipWhile(stream(numbers), i -> i > 5) .collect(Collectors.toList()); assertThat(skippedWhileGreaterThan5).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
В Java 9 далее, dropWhile () в стандартных Поток API обеспечивает ту же функциональность, что и skipWhile () .
3.8. разворачиваться ()
разворачиваться () генерирует потенциально бесконечный поток, применяя пользовательский генератор к семенной стоимости, а затем к каждому генерируемому значению – поток может быть прекращен путем Optional.empty ():
Streamunfolded = StreamUtils .unfold(2, i -> (i < 100) ? Optional.of(i * i) : Optional.empty()); assertThat(unfolded.collect(Collectors.toList())) .containsExactly(2, 4, 16, 256);
3.9. Оконные()
оконные () создает несколько подмножей потока источника в качестве потока Список . Метод принимает исходный поток, размер окна и пропустить значение в качестве параметра.
Список длина равна оконные размер, в то время как кип значение определяет, где начинается подмножество по сравнению с предыдущим подмножеством:
Integer[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8 }; ListwindowedWithSkip1 = StreamUtils .windowed(stream(numbers), 3, 1) .collect(Collectors.toList()); assertThat(windowedWithSkip1) .containsExactly(asList(1, 2, 3), asList(2, 3, 4), asList(3, 4, 5), asList(4, 5, 6), asList(5, 6, 7));
Кроме того, последнее окно гарантированно будет нужного размера, как мы можем видеть в следующем примере:
ListwindowedWithSkip2 = StreamUtils.windowed(stream(numbers), 3, 2).collect(Collectors.toList()); assertThat(windowedWithSkip2).containsExactly(asList(1, 2, 3), asList(3, 4, 5), asList(5, 6, 7));
3.10. агрегат ()
Есть два агрегат () методы, которые работают совершенно по-разному.
Первая агрегат () группы вместе элементы равной ценности в соответствии с данной :
Integer[] numbers = { 1, 2, 2, 3, 4, 4, 4, 5 }; Listaggregated = StreamUtils .aggregate(Arrays.stream(numbers), (int1, int2) -> int1.compareTo(int2) == 0) .collect(Collectors.toList()); assertThat(aggregated).containsExactly(asList(1), asList(2, 2), asList(3), asList(4, 4, 4), asList(5));
Предикат получает ценности смежным образом. Таким образом, выше даст другой результат, если номер не заказан.
С другой стороны, второй агрегат () просто используется для группы элементов из источника потока в группы желаемого размера :
ListaggregatedFixSize = StreamUtils .aggregate(stream(numbers), 5) .collect(Collectors.toList()); assertThat(aggregatedFixSize).containsExactly(asList(1, 2, 2, 3, 4), asList(4, 4, 5));
3.11. агрегатОнлистУверение()
агрегатНаlistCondition () группы ценностей на основе предиката и текущего активного группового . Предикат дается в настоящее время активная группа в качестве Список и следующее значение. Затем он должен определить, должна ли группа продолжать работу или начать новую группу.
Следующий пример решает требование о совместной группе смежных значений в группе, где сумма значений в каждой группе не должна быть больше 5:
Integer[] numbers = { 1, 1, 2, 3, 4, 4, 5 }; Stream> aggregated = StreamUtils .aggregateOnListCondition(stream(numbers), (currentList, nextInt) -> currentList.stream().mapToInt(Integer::intValue).sum() + nextInt <= 5); assertThat(aggregated) .containsExactly(asList(1, 1, 2), asList(3), asList(4), asList(4), asList(5));
4. Потоковая
Пример Поток не является многоразовым. По этой причине Потоковая обеспечивает многоразовые потоки путем обертывания и разоблачения тех же методов, что и Поток :
Streamables = Streamable.of("a", "b", "c", "d"); List collected1 = s.collect(Collectors.toList()); List collected2 = s.collect(Collectors.toList()); assertThat(collected1).hasSize(4); assertThat(collected2).hasSize(4);
5. КоллекционерУтилы
КоллекционерУтилс дополняет стандартную Коллекционеры добавив несколько полезных методов сбора.
5.1. maxBy () и minBy ()
maxBy () находит максимальное значение в потоке, используя предоставленную логику проекции :
Streamclubs = Stream.of("Juventus", "Barcelona", "PSG"); Optional longestName = clubs.collect(CollectorUtils.maxBy(String::length)); assertThat(longestName).contains("Barcelona");
В отличие от этого, minBy () находит минимальное значение, используя предоставленную логику проекции .
5.2. уникальный()
уникальный () коллекционер делает очень простую вещь: он возвращает единственное значение, если данный поток имеет ровно 1 элемент:
StreamsingleElement = Stream.of(1); Optional unique = singleElement.collect(CollectorUtils.unique()); assertThat(unique).contains(1);
В противном случае, уникальный () сделает исключение:
Stream multipleElement = Stream.of(1, 2, 3); assertThatExceptionOfType(NonUniqueValueException.class).isThrownBy(() -> { multipleElement.collect(CollectorUtils.unique()); });
6. Заключение
В этой статье мы узнали, как библиотека Protonpack расширяет API Java Stream, чтобы упростить его использование. Он добавляет полезные методы, которые мы могли бы обычно использовать, но отсутствуют в стандартном API.
Начиная с Java 9, некоторые функциональные возможности, предоставляемые Protonpack, будут доступны в стандартном API Stream.
Как обычно, код можно найти более на Github .