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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user