Merge pull request #12590 from etrandafir93/features/BAEL-5674-streams-multiple-vs-single-filters
BAEL-5674: added code examples for the article
This commit is contained in:
commit
ff63982af2
|
@ -53,6 +53,12 @@
|
||||||
<artifactId>jmh-generator-annprocess</artifactId>
|
<artifactId>jmh-generator-annprocess</artifactId>
|
||||||
<version>${jmh-generator.version}</version>
|
<version>${jmh-generator.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.12.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Integer, Long> 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<Student> 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<Student> 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<Student> 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<Student> filteredStream = students.stream()
|
||||||
|
.filter(Student::isEligibleForScholarship)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
assertThat(filteredStream).containsExactly(mathStudent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Integer> 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<Integer> getMarks() {
|
||||||
|
return marks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMarks(List<Integer> marks) {
|
||||||
|
this.marks = marks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Profile getProfile() {
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfile(Profile profile) {
|
||||||
|
this.profile = profile;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue