diff --git a/core-java-modules/core-java-streams-4/pom.xml b/core-java-modules/core-java-streams-4/pom.xml
index 65de1d666c..ed4603796d 100644
--- a/core-java-modules/core-java-streams-4/pom.xml
+++ b/core-java-modules/core-java-streams-4/pom.xml
@@ -53,6 +53,12 @@
jmh-generator-annprocess
${jmh-generator.version}
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
+ test
+
diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionFilterOrderUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionFilterOrderUnitTest.java
new file mode 100644
index 0000000000..fcecc36631
--- /dev/null
+++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionFilterOrderUnitTest.java
@@ -0,0 +1,89 @@
+package com.baeldung.streams.multiplefilters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.IntStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class MultipleFiltersVsComplexConditionFilterOrderUnitTest {
+
+ AtomicInteger numberOfOperations = new AtomicInteger();
+
+ @Before
+ public void beforeEach() {
+ numberOfOperations.set(0);
+ }
+
+ @Test
+ public void givenWrongFilterOrder_whenUsingMultipleFilters_shouldEvaluateManyConditions() {
+ long filteredStreamSize = IntStream.range(0, 100)
+ .boxed()
+ .filter(this::isEvenNumber)
+ .filter(this::isSmallerThanTwenty)
+ .count();
+
+ assertThat(filteredStreamSize).isEqualTo(10);
+ assertThat(numberOfOperations).hasValue(150);
+ }
+
+ @Test
+ public void givenWrongFilterOrder_whenUsingSingleFilters_shouldEvaluateManyConditions() {
+ long filteredStreamSize = IntStream.range(0, 100)
+ .boxed()
+ .filter(i -> isEvenNumber(i) && isSmallerThanTwenty(i))
+ .count();
+
+ assertThat(filteredStreamSize).isEqualTo(10);
+ assertThat(numberOfOperations).hasValue(150);
+ }
+
+ @Test
+ public void givenCorrectFilterOrder_whenUsingMultipleFilters_shouldEvaluateFewerConditions() {
+ long filteredStreamSize = IntStream.range(0, 100)
+ .boxed()
+ .filter(this::isSmallerThanTwenty)
+ .filter(this::isEvenNumber)
+ .count();
+
+ assertThat(filteredStreamSize).isEqualTo(10);
+ assertThat(numberOfOperations).hasValue(120);
+ }
+
+ @Test
+ public void givenCorrectFilterOrder_whenUsingHavingASlowCondition_shouldEvaluateFewerConditions() {
+ long filteredStreamSize = IntStream.range(0, 100)
+ .boxed()
+ .filter(this::isSmallerThanTwenty)
+ .filter(this::isEvenNumber)
+ .filter(this::verySlowFilter)
+ .count();
+
+ assertThat(filteredStreamSize).isEqualTo(10);
+ assertThat(numberOfOperations).hasValue(130);
+ }
+
+ private boolean isEvenNumber(int i) {
+ numberOfOperations.incrementAndGet();
+ return i % 2 == 0;
+ }
+
+ private boolean isSmallerThanTwenty(int i) {
+ numberOfOperations.incrementAndGet();
+ return i < 20;
+ }
+
+ private boolean verySlowFilter(int i) {
+ numberOfOperations.incrementAndGet();
+ // commented the Thread.sleep() not to slow down the pipeline.
+ // try {
+ // Thread.sleep(1000);
+ // } catch (InterruptedException e) {
+ // throw new RuntimeException(e);
+ // }
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionFilterPerformanceIntegrationTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionFilterPerformanceIntegrationTest.java
new file mode 100644
index 0000000000..1362431b07
--- /dev/null
+++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionFilterPerformanceIntegrationTest.java
@@ -0,0 +1,130 @@
+package com.baeldung.streams.multiplefilters;
+
+import java.text.MessageFormat;
+import java.util.function.Function;
+import java.util.stream.IntStream;
+
+import org.apache.commons.lang3.time.StopWatch;
+import org.junit.Test;
+
+public class MultipleFiltersVsComplexConditionFilterPerformanceIntegrationTest {
+
+// this test is slow, avoid running it on pipeline
+ @Test
+ public void measureProcessingTimeForEachSolution() {
+
+ averageMultipleMeasurements("Stream with Multiple Filters", this::measureTimeForMultipleFilters, 10_000);
+ averageMultipleMeasurements("Stream with Multiple Filters", this::measureTimeForMultipleFilters, 100_000);
+ averageMultipleMeasurements("Stream with Multiple Filters", this::measureTimeForMultipleFilters, 10_00_000);
+ averageMultipleMeasurements("Stream with Multiple Filters", this::measureTimeForMultipleFilters, 1_0000_000);
+
+ averageMultipleMeasurements("Stream with Complex Condition", this::measureTimeForComplexCondition, 10_000);
+ averageMultipleMeasurements("Stream with Complex Condition", this::measureTimeForComplexCondition, 100_000);
+ averageMultipleMeasurements("Stream with Complex Condition", this::measureTimeForComplexCondition, 10_00_000);
+ averageMultipleMeasurements("Stream with Complex Condition", this::measureTimeForComplexCondition, 1_0000_000);
+
+ averageMultipleMeasurements("Parallel Stream with Multiple Filters", this::measureTimeForParallelStreamWithMultipleFilters, 10_000);
+ averageMultipleMeasurements("Parallel Stream with Multiple Filters", this::measureTimeForParallelStreamWithMultipleFilters, 100_000);
+ averageMultipleMeasurements("Parallel Stream with Multiple Filters", this::measureTimeForParallelStreamWithMultipleFilters, 10_00_000);
+ averageMultipleMeasurements("Parallel Stream with Multiple Filters", this::measureTimeForParallelStreamWithMultipleFilters, 1_0000_000);
+
+ averageMultipleMeasurements("Parallel Stream with Complex Condition", this::measureTimeForParallelStreamWithComplexCondition, 10_000);
+ averageMultipleMeasurements("Parallel Stream with Complex Condition", this::measureTimeForParallelStreamWithComplexCondition, 100_000);
+ averageMultipleMeasurements("Parallel Stream with Complex Condition", this::measureTimeForParallelStreamWithComplexCondition, 10_00_000);
+ averageMultipleMeasurements("Parallel Stream with Complex Condition", this::measureTimeForParallelStreamWithComplexCondition, 1_0000_000);
+
+ averageMultipleMeasurements("Old For Loop with Complex Condition", this::measureTimeForOlfForLoopWithComplexCondition, 10_000);
+ averageMultipleMeasurements("Old For Loop with Complex Condition", this::measureTimeForOlfForLoopWithComplexCondition, 100_000);
+ averageMultipleMeasurements("Old For Loop with Complex Condition", this::measureTimeForOlfForLoopWithComplexCondition, 10_00_000);
+ averageMultipleMeasurements("Old For Loop with Complex Condition", this::measureTimeForOlfForLoopWithComplexCondition, 1_0000_000);
+
+ }
+
+ private void averageMultipleMeasurements(String measurementName, Function measurement, int range) {
+ double avgTime = IntStream.range(0, 100)
+ .mapToLong(i -> measurement.apply(range))
+ .average()
+ .orElseThrow();
+
+ System.out.println(MessageFormat.format("{0}; Stream size: {1}; Processing Time (ms): {2}", measurementName, range, avgTime));
+ }
+
+ public long measureTimeForMultipleFilters(int range) {
+ StopWatch watch = new StopWatch();
+ watch.start();
+
+ IntStream.range(0, range)
+ .boxed()
+ .filter(i -> i != 10)
+ .filter(i -> i != 20)
+ .filter(i -> i != 30)
+ .filter(i -> i != 40)
+ .filter(i -> i != 50)
+ .filter(i -> i != 60)
+ .count();
+
+ watch.stop();
+ return watch.getTime();
+ }
+
+ public long measureTimeForParallelStreamWithMultipleFilters(int range) {
+ StopWatch watch = new StopWatch();
+ watch.start();
+
+ IntStream.range(0, range)
+ .boxed()
+ .parallel()
+ .filter(i -> i != 10)
+ .filter(i -> i != 20)
+ .filter(i -> i != 30)
+ .filter(i -> i != 40)
+ .filter(i -> i != 50)
+ .filter(i -> i != 60)
+ .count();
+
+ watch.stop();
+ return watch.getTime();
+ }
+
+ public long measureTimeForComplexCondition(int range) {
+ StopWatch watch = new StopWatch();
+ watch.start();
+
+ IntStream.range(0, range)
+ .boxed()
+ .filter(i -> i != 10 && i != 20 && i != 30 && i != 40 && i != 50 && i != 60)
+ .count();
+
+ watch.stop();
+ return watch.getTime();
+ }
+
+ public long measureTimeForParallelStreamWithComplexCondition(int range) {
+ StopWatch watch = new StopWatch();
+ watch.start();
+
+ IntStream.range(0, range)
+ .boxed()
+ .parallel()
+ .filter(i -> i != 10 && i != 20 && i != 30 && i != 40 && i != 50 && i != 60)
+ .count();
+
+ watch.stop();
+ return watch.getTime();
+ }
+
+ public long measureTimeForOlfForLoopWithComplexCondition(int range) {
+ StopWatch watch = new StopWatch();
+ watch.start();
+
+ int count = 0;
+ for (int i = 0; i <= range; i++) {
+ if (i != 10 && i != 20 && i != 30 && i != 40 && i != 50 && i != 60) {
+ count++;
+ }
+ }
+
+ watch.stop();
+ return watch.getTime();
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionReadabilityUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionReadabilityUnitTest.java
new file mode 100644
index 0000000000..80fdb8a30a
--- /dev/null
+++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/MultipleFiltersVsComplexConditionReadabilityUnitTest.java
@@ -0,0 +1,65 @@
+package com.baeldung.streams.multiplefilters;
+
+import static java.util.function.Predicate.not;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class MultipleFiltersVsComplexConditionReadabilityUnitTest {
+
+ private List students;
+ private Student mathStudent;
+
+ @Before
+ public void beforeEach() {
+ this.mathStudent = new Student();
+ mathStudent.setName("John Doe");
+ mathStudent.setYear(3);
+ mathStudent.setProfile(Student.Profile.MATH);
+ mathStudent.setMarks(List.of(80, 90, 77, 95, 100));
+
+ Student csStudent = new Student();
+ csStudent.setName("Paul Atreides");
+ csStudent.setYear(2);
+ csStudent.setProfile(Student.Profile.COMPUTER_SCIENCE);
+ csStudent.setMarks(List.of(30, 40, 60));
+
+ this.students = List.of(mathStudent, csStudent);
+ }
+
+ @Test
+ public void whenUsingMultipleFilters_dataShouldBeFiltered() {
+ List filteredStream = students.stream()
+ .filter(s -> s.getMarksAverage() > 50)
+ .filter(s -> s.getMarks().size() > 3)
+ .filter(not(s -> s.getProfile() == Student.Profile.PHYSICS))
+ .collect(Collectors.toList());
+
+ assertThat(filteredStream).containsExactly(mathStudent);
+ }
+
+ @Test
+ public void whenUsingSingleComplexFilter_dataShouldBeFiltered() {
+ List filteredStream = students.stream()
+ .filter(s -> s.getMarksAverage() > 50
+ && s.getMarks().size() > 3
+ && s.getProfile() != Student.Profile.PHYSICS)
+ .collect(Collectors.toList());
+
+ assertThat(filteredStream).containsExactly(mathStudent);
+ }
+
+ @Test
+ public void whenUsingSingleComplexFilterExtracted_dataShouldBeFiltered() {
+ List filteredStream = students.stream()
+ .filter(Student::isEligibleForScholarship)
+ .collect(Collectors.toList());
+
+ assertThat(filteredStream).containsExactly(mathStudent);
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/Student.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/Student.java
new file mode 100644
index 0000000000..0e6b77ae2c
--- /dev/null
+++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/multiplefilters/Student.java
@@ -0,0 +1,60 @@
+package com.baeldung.streams.multiplefilters;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Student {
+
+ private String name;
+ private int year;
+ private List marks;
+ private Profile profile;
+
+ public enum Profile {
+ COMPUTER_SCIENCE,
+ MATH,
+ PHYSICS
+ }
+
+ public double getMarksAverage() {
+ return marks.stream().collect(Collectors.averagingInt(m -> m));
+ }
+
+ public boolean isEligibleForScholarship() {
+ return getMarksAverage() > 50
+ && marks.size() > 3
+ && profile != Profile.PHYSICS;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ public List getMarks() {
+ return marks;
+ }
+
+ public void setMarks(List marks) {
+ this.marks = marks;
+ }
+
+ public Profile getProfile() {
+ return profile;
+ }
+
+ public void setProfile(Profile profile) {
+ this.profile = profile;
+ }
+}
\ No newline at end of file