diff --git a/java-streams/pom.xml b/java-streams/pom.xml
index 023a5f695b..e4670c268d 100644
--- a/java-streams/pom.xml
+++ b/java-streams/pom.xml
@@ -105,7 +105,7 @@
3.5
1.16.12
0.9.0
- 1.13
+ 1.15
0.6.5
2.10
diff --git a/java-streams/src/test/java/com/baeldung/protonpack/ProtonpackUnitTest.java b/java-streams/src/test/java/com/baeldung/protonpack/ProtonpackUnitTest.java
new file mode 100644
index 0000000000..1b64c8924a
--- /dev/null
+++ b/java-streams/src/test/java/com/baeldung/protonpack/ProtonpackUnitTest.java
@@ -0,0 +1,209 @@
+package com.baeldung.protonpack;
+
+import com.codepoetics.protonpack.Indexed;
+import com.codepoetics.protonpack.StreamUtils;
+import com.codepoetics.protonpack.collectors.CollectorUtils;
+import com.codepoetics.protonpack.collectors.NonUniqueValueException;
+import com.codepoetics.protonpack.selectors.Selector;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.util.Arrays.asList;
+import static java.util.Arrays.stream;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+@SuppressWarnings("unchecked")
+public class ProtonpackUnitTest {
+ @Test
+ public void whenTakeWhile_thenTakenWhile() {
+ Stream streamOfInt = Stream.iterate(1, i -> i + 1);
+ List result = StreamUtils.takeWhile(streamOfInt, i -> i < 5).collect(Collectors.toList());
+ assertThat(result).contains(1, 2, 3, 4);
+ }
+
+ @Test
+ public void whenTakeUntil_thenTakenUntil() {
+ Stream streamOfInt = Stream.iterate(1, i -> i + 1);
+ List result = StreamUtils.takeUntil(streamOfInt, i -> i > 50).collect(Collectors.toList());
+ assertThat(result).contains(10, 20, 30, 40);
+ }
+
+ @Test
+ public void givenMultipleStream_whenZipped_thenZipped() {
+ String[] clubs = { "Juventus", "Barcelona", "Liverpool", "PSG" };
+ String[] players = { "Ronaldo", "Messi", "Salah" };
+ Set zippedFrom2Sources = StreamUtils.zip(stream(clubs), stream(players), (club, player) -> club + " " + player)
+ .collect(Collectors.toSet());
+ assertThat(zippedFrom2Sources).contains("Juventus Ronaldo", "Barcelona Messi", "Liverpool Salah");
+
+ String[] leagues = { "Serie A", "La Liga", "Premier League" };
+ Set zippedFrom3Sources = 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");
+ }
+
+ @Test
+ public void whenZippedWithIndex_thenZippedWithIndex() {
+ Stream streamOfClubs = 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"));
+ }
+
+ @Test
+ public void givenMultipleStream_whenMerged_thenMerged() {
+ Stream streamOfClubs = 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");
+ }
+
+ @Test
+ public void givenMultipleStream_whenMergedToList_thenMergedToList() {
+ Stream streamOfClubs = Stream.of("Juventus", "Barcelona", "PSG");
+ Stream streamOfPlayers = Stream.of("Ronaldo", "Messi");
+
+ List> mergedListOfList = StreamUtils.mergeToList(streamOfClubs, streamOfPlayers)
+ .collect(Collectors.toList());
+ assertThat(mergedListOfList.get(0)).isInstanceOf(List.class);
+ assertThat(mergedListOfList.get(0)).containsExactly("Juventus", "Ronaldo");
+ assertThat(mergedListOfList.get(1)).containsExactly("Barcelona", "Messi");
+ assertThat(mergedListOfList.get(2)).containsExactly("PSG");
+ }
+
+ @Test
+ public void givenMultipleStream_whenInterleaved_thenInterleaved() {
+ Stream streamOfClubs = Stream.of("Juventus", "Barcelona", "Liverpool");
+ Stream streamOfPlayers = Stream.of("Ronaldo", "Messi");
+ Stream streamOfLeagues = Stream.of("Serie A", "La Liga");
+
+ AtomicInteger counter = new AtomicInteger(0);
+ Selector roundRobinSelector = (o) -> {
+ Object[] vals = (Object[]) o;
+ while (counter.get() >= vals.length || vals[counter.get()] == null) {
+ if (counter.incrementAndGet() >= vals.length)
+ counter.set(0);
+ }
+ return counter.getAndIncrement();
+ };
+ Stream interleavedStream = StreamUtils.interleave(roundRobinSelector, streamOfClubs, streamOfPlayers,
+ streamOfLeagues);
+ List interleavedList = interleavedStream.collect(Collectors.toList());
+ assertThat(interleavedList).containsExactly("Juventus", "Ronaldo", "Serie A", "Barcelona", "Messi", "La Liga",
+ "Liverpool");
+ }
+
+ @Test
+ public void whenSkippedUntil_thenSkippedUntil() {
+ 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);
+
+ List skippedUntilLessThanEquals5 = StreamUtils.skipUntil(stream(numbers), i -> i <= 5)
+ .collect(Collectors.toList());
+ assertThat(skippedUntilLessThanEquals5).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ }
+
+ @Test
+ public void whenSkippedWhile_thenSkippedWhile() {
+ 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);
+
+ 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);
+ }
+
+ @Test
+ public void givenFibonacciGenerator_whenUnfolded_thenUnfolded() {
+ AtomicInteger lastValue = new AtomicInteger(0);
+ Function> fibonacciGenerator = (i) -> (i < 10) ?
+ Optional.of(i + lastValue.getAndSet(i)) :
+ Optional.empty();
+
+ List fib = StreamUtils.unfold(1, fibonacciGenerator).collect(Collectors.toList());
+ assertThat(fib).containsExactly(1, 1, 2, 3, 5, 8, 13);
+ }
+
+ @Test
+ public void whenWindowed_thenWindowed() {
+ Integer[] numbers = { 1, 2, 3, 4, 5, 6, 7 };
+
+ List> windowedWithSkip1 = 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));
+
+ List> windowedWithSkip2 = StreamUtils.windowed(stream(numbers), 3, 2).collect(Collectors.toList());
+ assertThat(windowedWithSkip2).containsExactly(asList(1, 2, 3), asList(3, 4, 5), asList(5, 6, 7));
+ }
+
+ @Test
+ public void whenAggregated_thenAggregated() {
+ Integer[] numbers = { 1, 2, 2, 3, 4, 4, 4, 5 };
+ List> aggregated = StreamUtils.aggregate(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));
+
+ List> aggregatedFixSize = StreamUtils.aggregate(stream(numbers), 5).collect(Collectors.toList());
+ assertThat(aggregatedFixSize).containsExactly(asList(1, 2, 2, 3, 4), asList(4, 4, 5));
+ }
+
+ @Test
+ public void whenGroupedRun_thenGroupedRun() {
+ Integer[] numbers = { 1, 1, 2, 3, 4, 4, 5 };
+ List> grouped = StreamUtils.groupRuns(stream(numbers)).collect(Collectors.toList());
+ assertThat(grouped).containsExactly(asList(1, 1), asList(2), asList(3), asList(4, 4), asList(5));
+
+ Integer[] numbers2 = { 1, 2, 3, 1 };
+ List> grouped2 = StreamUtils.groupRuns(stream(numbers2)).collect(Collectors.toList());
+ assertThat(grouped2).containsExactly(asList(1), asList(2), asList(3), asList(1));
+ }
+
+ @Test
+ public void whenAggregatedOnListCondition_thenAggregatedOnListCondition() {
+ 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));
+ }
+
+ @Test
+ public void givenProjectionFunction_whenMaxedBy_thenMaxedBy() {
+ Stream clubs = Stream.of("Juventus", "Barcelona", "PSG");
+ Optional longestName = clubs.collect(CollectorUtils.maxBy(String::length));
+ assertThat(longestName.get()).isEqualTo("Barcelona");
+ }
+
+ @Test
+ public void givenStreamOfMultipleElem_whenUniqueCollector_thenValueReturned() {
+ Stream singleElement = Stream.of(1);
+ Optional unique = singleElement.collect(CollectorUtils.unique());
+ assertThat(unique.get()).isEqualTo(1);
+
+ }
+
+ @Test
+ public void givenStreamOfMultipleElem_whenUniqueCollector_thenExceptionThrown() {
+ Stream multipleElement = Stream.of(1, 2, 3);
+ assertThatExceptionOfType(NonUniqueValueException.class).isThrownBy(() -> {
+ multipleElement.collect(CollectorUtils.unique());
+ });
+ }
+
+}