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> | ||||
|             <version>${jmh-generator.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.commons</groupId> | ||||
|             <artifactId>commons-lang3</artifactId> | ||||
|             <version>3.12.0</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user