Skip to content

Commit c4259cb

Browse files
Merge pull request eugenp#12590 from etrandafir93/features/BAEL-5674-streams-multiple-vs-single-filters
BAEL-5674: added code examples for the article
2 parents 86c6881 + 25c2c1f commit c4259cb

5 files changed

Lines changed: 350 additions & 0 deletions

File tree

core-java-modules/core-java-streams-4/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
<artifactId>jmh-generator-annprocess</artifactId>
5454
<version>${jmh-generator.version}</version>
5555
</dependency>
56+
<dependency>
57+
<groupId>org.apache.commons</groupId>
58+
<artifactId>commons-lang3</artifactId>
59+
<version>3.12.0</version>
60+
<scope>test</scope>
61+
</dependency>
5662
</dependencies>
5763

5864
<build>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.baeldung.streams.multiplefilters;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.util.concurrent.atomic.AtomicInteger;
6+
import java.util.stream.IntStream;
7+
8+
import org.junit.Before;
9+
import org.junit.Test;
10+
11+
public class MultipleFiltersVsComplexConditionFilterOrderUnitTest {
12+
13+
AtomicInteger numberOfOperations = new AtomicInteger();
14+
15+
@Before
16+
public void beforeEach() {
17+
numberOfOperations.set(0);
18+
}
19+
20+
@Test
21+
public void givenWrongFilterOrder_whenUsingMultipleFilters_shouldEvaluateManyConditions() {
22+
long filteredStreamSize = IntStream.range(0, 100)
23+
.boxed()
24+
.filter(this::isEvenNumber)
25+
.filter(this::isSmallerThanTwenty)
26+
.count();
27+
28+
assertThat(filteredStreamSize).isEqualTo(10);
29+
assertThat(numberOfOperations).hasValue(150);
30+
}
31+
32+
@Test
33+
public void givenWrongFilterOrder_whenUsingSingleFilters_shouldEvaluateManyConditions() {
34+
long filteredStreamSize = IntStream.range(0, 100)
35+
.boxed()
36+
.filter(i -> isEvenNumber(i) && isSmallerThanTwenty(i))
37+
.count();
38+
39+
assertThat(filteredStreamSize).isEqualTo(10);
40+
assertThat(numberOfOperations).hasValue(150);
41+
}
42+
43+
@Test
44+
public void givenCorrectFilterOrder_whenUsingMultipleFilters_shouldEvaluateFewerConditions() {
45+
long filteredStreamSize = IntStream.range(0, 100)
46+
.boxed()
47+
.filter(this::isSmallerThanTwenty)
48+
.filter(this::isEvenNumber)
49+
.count();
50+
51+
assertThat(filteredStreamSize).isEqualTo(10);
52+
assertThat(numberOfOperations).hasValue(120);
53+
}
54+
55+
@Test
56+
public void givenCorrectFilterOrder_whenUsingHavingASlowCondition_shouldEvaluateFewerConditions() {
57+
long filteredStreamSize = IntStream.range(0, 100)
58+
.boxed()
59+
.filter(this::isSmallerThanTwenty)
60+
.filter(this::isEvenNumber)
61+
.filter(this::verySlowFilter)
62+
.count();
63+
64+
assertThat(filteredStreamSize).isEqualTo(10);
65+
assertThat(numberOfOperations).hasValue(130);
66+
}
67+
68+
private boolean isEvenNumber(int i) {
69+
numberOfOperations.incrementAndGet();
70+
return i % 2 == 0;
71+
}
72+
73+
private boolean isSmallerThanTwenty(int i) {
74+
numberOfOperations.incrementAndGet();
75+
return i < 20;
76+
}
77+
78+
private boolean verySlowFilter(int i) {
79+
numberOfOperations.incrementAndGet();
80+
// commented the Thread.sleep() not to slow down the pipeline.
81+
// try {
82+
// Thread.sleep(1000);
83+
// } catch (InterruptedException e) {
84+
// throw new RuntimeException(e);
85+
// }
86+
return true;
87+
}
88+
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package com.baeldung.streams.multiplefilters;
2+
3+
import java.text.MessageFormat;
4+
import java.util.function.Function;
5+
import java.util.stream.IntStream;
6+
7+
import org.apache.commons.lang3.time.StopWatch;
8+
import org.junit.Test;
9+
10+
public class MultipleFiltersVsComplexConditionFilterPerformanceIntegrationTest {
11+
12+
// this test is slow, avoid running it on pipeline
13+
@Test
14+
public void measureProcessingTimeForEachSolution() {
15+
16+
averageMultipleMeasurements("Stream with Multiple Filters", this::measureTimeForMultipleFilters, 10_000);
17+
averageMultipleMeasurements("Stream with Multiple Filters", this::measureTimeForMultipleFilters, 100_000);
18+
averageMultipleMeasurements("Stream with Multiple Filters", this::measureTimeForMultipleFilters, 10_00_000);
19+
averageMultipleMeasurements("Stream with Multiple Filters", this::measureTimeForMultipleFilters, 1_0000_000);
20+
21+
averageMultipleMeasurements("Stream with Complex Condition", this::measureTimeForComplexCondition, 10_000);
22+
averageMultipleMeasurements("Stream with Complex Condition", this::measureTimeForComplexCondition, 100_000);
23+
averageMultipleMeasurements("Stream with Complex Condition", this::measureTimeForComplexCondition, 10_00_000);
24+
averageMultipleMeasurements("Stream with Complex Condition", this::measureTimeForComplexCondition, 1_0000_000);
25+
26+
averageMultipleMeasurements("Parallel Stream with Multiple Filters", this::measureTimeForParallelStreamWithMultipleFilters, 10_000);
27+
averageMultipleMeasurements("Parallel Stream with Multiple Filters", this::measureTimeForParallelStreamWithMultipleFilters, 100_000);
28+
averageMultipleMeasurements("Parallel Stream with Multiple Filters", this::measureTimeForParallelStreamWithMultipleFilters, 10_00_000);
29+
averageMultipleMeasurements("Parallel Stream with Multiple Filters", this::measureTimeForParallelStreamWithMultipleFilters, 1_0000_000);
30+
31+
averageMultipleMeasurements("Parallel Stream with Complex Condition", this::measureTimeForParallelStreamWithComplexCondition, 10_000);
32+
averageMultipleMeasurements("Parallel Stream with Complex Condition", this::measureTimeForParallelStreamWithComplexCondition, 100_000);
33+
averageMultipleMeasurements("Parallel Stream with Complex Condition", this::measureTimeForParallelStreamWithComplexCondition, 10_00_000);
34+
averageMultipleMeasurements("Parallel Stream with Complex Condition", this::measureTimeForParallelStreamWithComplexCondition, 1_0000_000);
35+
36+
averageMultipleMeasurements("Old For Loop with Complex Condition", this::measureTimeForOlfForLoopWithComplexCondition, 10_000);
37+
averageMultipleMeasurements("Old For Loop with Complex Condition", this::measureTimeForOlfForLoopWithComplexCondition, 100_000);
38+
averageMultipleMeasurements("Old For Loop with Complex Condition", this::measureTimeForOlfForLoopWithComplexCondition, 10_00_000);
39+
averageMultipleMeasurements("Old For Loop with Complex Condition", this::measureTimeForOlfForLoopWithComplexCondition, 1_0000_000);
40+
41+
}
42+
43+
private void averageMultipleMeasurements(String measurementName, Function<Integer, Long> measurement, int range) {
44+
double avgTime = IntStream.range(0, 100)
45+
.mapToLong(i -> measurement.apply(range))
46+
.average()
47+
.orElseThrow();
48+
49+
System.out.println(MessageFormat.format("{0}; Stream size: {1}; Processing Time (ms): {2}", measurementName, range, avgTime));
50+
}
51+
52+
public long measureTimeForMultipleFilters(int range) {
53+
StopWatch watch = new StopWatch();
54+
watch.start();
55+
56+
IntStream.range(0, range)
57+
.boxed()
58+
.filter(i -> i != 10)
59+
.filter(i -> i != 20)
60+
.filter(i -> i != 30)
61+
.filter(i -> i != 40)
62+
.filter(i -> i != 50)
63+
.filter(i -> i != 60)
64+
.count();
65+
66+
watch.stop();
67+
return watch.getTime();
68+
}
69+
70+
public long measureTimeForParallelStreamWithMultipleFilters(int range) {
71+
StopWatch watch = new StopWatch();
72+
watch.start();
73+
74+
IntStream.range(0, range)
75+
.boxed()
76+
.parallel()
77+
.filter(i -> i != 10)
78+
.filter(i -> i != 20)
79+
.filter(i -> i != 30)
80+
.filter(i -> i != 40)
81+
.filter(i -> i != 50)
82+
.filter(i -> i != 60)
83+
.count();
84+
85+
watch.stop();
86+
return watch.getTime();
87+
}
88+
89+
public long measureTimeForComplexCondition(int range) {
90+
StopWatch watch = new StopWatch();
91+
watch.start();
92+
93+
IntStream.range(0, range)
94+
.boxed()
95+
.filter(i -> i != 10 && i != 20 && i != 30 && i != 40 && i != 50 && i != 60)
96+
.count();
97+
98+
watch.stop();
99+
return watch.getTime();
100+
}
101+
102+
public long measureTimeForParallelStreamWithComplexCondition(int range) {
103+
StopWatch watch = new StopWatch();
104+
watch.start();
105+
106+
IntStream.range(0, range)
107+
.boxed()
108+
.parallel()
109+
.filter(i -> i != 10 && i != 20 && i != 30 && i != 40 && i != 50 && i != 60)
110+
.count();
111+
112+
watch.stop();
113+
return watch.getTime();
114+
}
115+
116+
public long measureTimeForOlfForLoopWithComplexCondition(int range) {
117+
StopWatch watch = new StopWatch();
118+
watch.start();
119+
120+
int count = 0;
121+
for (int i = 0; i <= range; i++) {
122+
if (i != 10 && i != 20 && i != 30 && i != 40 && i != 50 && i != 60) {
123+
count++;
124+
}
125+
}
126+
127+
watch.stop();
128+
return watch.getTime();
129+
}
130+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.baeldung.streams.multiplefilters;
2+
3+
import static java.util.function.Predicate.not;
4+
import static org.assertj.core.api.Assertions.assertThat;
5+
6+
import java.util.List;
7+
import java.util.stream.Collectors;
8+
9+
import org.junit.Before;
10+
import org.junit.Test;
11+
12+
public class MultipleFiltersVsComplexConditionReadabilityUnitTest {
13+
14+
private List<Student> students;
15+
private Student mathStudent;
16+
17+
@Before
18+
public void beforeEach() {
19+
this.mathStudent = new Student();
20+
mathStudent.setName("John Doe");
21+
mathStudent.setYear(3);
22+
mathStudent.setProfile(Student.Profile.MATH);
23+
mathStudent.setMarks(List.of(80, 90, 77, 95, 100));
24+
25+
Student csStudent = new Student();
26+
csStudent.setName("Paul Atreides");
27+
csStudent.setYear(2);
28+
csStudent.setProfile(Student.Profile.COMPUTER_SCIENCE);
29+
csStudent.setMarks(List.of(30, 40, 60));
30+
31+
this.students = List.of(mathStudent, csStudent);
32+
}
33+
34+
@Test
35+
public void whenUsingMultipleFilters_dataShouldBeFiltered() {
36+
List<Student> filteredStream = students.stream()
37+
.filter(s -> s.getMarksAverage() > 50)
38+
.filter(s -> s.getMarks().size() > 3)
39+
.filter(not(s -> s.getProfile() == Student.Profile.PHYSICS))
40+
.collect(Collectors.toList());
41+
42+
assertThat(filteredStream).containsExactly(mathStudent);
43+
}
44+
45+
@Test
46+
public void whenUsingSingleComplexFilter_dataShouldBeFiltered() {
47+
List<Student> filteredStream = students.stream()
48+
.filter(s -> s.getMarksAverage() > 50
49+
&& s.getMarks().size() > 3
50+
&& s.getProfile() != Student.Profile.PHYSICS)
51+
.collect(Collectors.toList());
52+
53+
assertThat(filteredStream).containsExactly(mathStudent);
54+
}
55+
56+
@Test
57+
public void whenUsingSingleComplexFilterExtracted_dataShouldBeFiltered() {
58+
List<Student> filteredStream = students.stream()
59+
.filter(Student::isEligibleForScholarship)
60+
.collect(Collectors.toList());
61+
62+
assertThat(filteredStream).containsExactly(mathStudent);
63+
}
64+
65+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.baeldung.streams.multiplefilters;
2+
3+
import java.util.List;
4+
import java.util.stream.Collectors;
5+
6+
public class Student {
7+
8+
private String name;
9+
private int year;
10+
private List<Integer> marks;
11+
private Profile profile;
12+
13+
public enum Profile {
14+
COMPUTER_SCIENCE,
15+
MATH,
16+
PHYSICS
17+
}
18+
19+
public double getMarksAverage() {
20+
return marks.stream().collect(Collectors.averagingInt(m -> m));
21+
}
22+
23+
public boolean isEligibleForScholarship() {
24+
return getMarksAverage() > 50
25+
&& marks.size() > 3
26+
&& profile != Profile.PHYSICS;
27+
}
28+
29+
public String getName() {
30+
return name;
31+
}
32+
33+
public void setName(String name) {
34+
this.name = name;
35+
}
36+
37+
public int getYear() {
38+
return year;
39+
}
40+
41+
public void setYear(int year) {
42+
this.year = year;
43+
}
44+
45+
public List<Integer> getMarks() {
46+
return marks;
47+
}
48+
49+
public void setMarks(List<Integer> marks) {
50+
this.marks = marks;
51+
}
52+
53+
public Profile getProfile() {
54+
return profile;
55+
}
56+
57+
public void setProfile(Profile profile) {
58+
this.profile = profile;
59+
}
60+
}

0 commit comments

Comments
 (0)