diff --git a/core-java-modules/core-java-streams-4/pom.xml b/core-java-modules/core-java-streams-4/pom.xml index beed277f78..65de1d666c 100644 --- a/core-java-modules/core-java-streams-4/pom.xml +++ b/core-java-modules/core-java-streams-4/pom.xml @@ -43,6 +43,16 @@ 3.23.1 test + + org.openjdk.jmh + jmh-core + ${jmh-core.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh-generator.version} + diff --git a/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/BenchmarkRunner.java b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/BenchmarkRunner.java new file mode 100644 index 0000000000..327bdc4df3 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/BenchmarkRunner.java @@ -0,0 +1,56 @@ +package com.baeldung.streams.filteronlyoneelement; + +import java.util.function.Predicate; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.infra.Blackhole; + +public class BenchmarkRunner { + + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } + + @State(Scope.Benchmark) + public static class MyState { + final Stream getIntegers() { + return IntStream.range(1, 1000000) + .boxed(); + } + + final Predicate PREDICATE = i -> i == 751879; + } + + @Benchmark + public void evaluateFindUniqueElementMatchingPredicate_WithReduction(Blackhole blackhole, MyState state) { + blackhole.consume(FilterUtils.findUniqueElementMatchingPredicate_WithReduction(state.getIntegers(), state.PREDICATE)); + } + + @Benchmark + public void evaluateFindUniqueElementMatchingPredicate_WithCollectingAndThen(Blackhole blackhole, MyState state) { + blackhole.consume(FilterUtils.findUniqueElementMatchingPredicate_WithCollectingAndThen(state.getIntegers(), state.PREDICATE)); + } + + @Benchmark + public void evaluateGetUniqueElementMatchingPredicate_WithReduction(Blackhole blackhole, MyState state) { + try { + FilterUtils.getUniqueElementMatchingPredicate_WithReduction(state.getIntegers(), state.PREDICATE); + } catch (IllegalStateException exception) { + blackhole.consume(exception); + } + } + + @Benchmark + public void evaluateGetUniqueElementMatchingPredicate_WithCollectingAndThen(Blackhole blackhole, MyState state) { + try { + FilterUtils.getUniqueElementMatchingPredicate_WithCollectingAndThen(state.getIntegers(), state.PREDICATE); + } catch (IllegalStateException exception) { + blackhole.consume(exception); + } + } + +} diff --git a/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/FilterUtils.java b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/FilterUtils.java new file mode 100644 index 0000000000..65905a7bc4 --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/main/java/com/baeldung/streams/filteronlyoneelement/FilterUtils.java @@ -0,0 +1,50 @@ +package com.baeldung.streams.filteronlyoneelement; + +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class FilterUtils { + + public static Optional findUniqueElementMatchingPredicate_WithReduction(Stream elements, Predicate predicate) { + return elements.filter(predicate) + .collect(Collectors.reducing((a, b) -> null)); + } + + public static T getUniqueElementMatchingPredicate_WithReduction(Stream elements, Predicate predicate) { + return elements.filter(predicate) + .reduce((a, b) -> { + throw new IllegalStateException("Too many elements match the predicate"); + }) + .orElseThrow(() -> new IllegalStateException("No element matches the predicate")); + } + + public static Optional findUniqueElementMatchingPredicate_WithCollectingAndThen(Stream elements, Predicate predicate) { + return elements.filter(predicate) + .collect(Collectors.collectingAndThen(Collectors.toList(), list -> Optional.ofNullable(findUniqueElement(list)))); + } + + private static T findUniqueElement(List elements) { + if (elements.size() == 1) { + return elements.get(0); + } + return null; + } + + public static T getUniqueElementMatchingPredicate_WithCollectingAndThen(Stream elements, Predicate predicate) { + return elements.filter(predicate) + .collect(Collectors.collectingAndThen(Collectors.toList(), FilterUtils::getUniqueElement)); + } + + private static T getUniqueElement(List elements) { + if (elements.size() > 1) { + throw new IllegalStateException("Too many elements match the predicate"); + } else if (elements.size() == 0) { + throw new IllegalStateException("No element matches the predicate"); + } + return elements.get(0); + } + +} diff --git a/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/filteronlyoneelement/FilterUtilsUnitTest.java b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/filteronlyoneelement/FilterUtilsUnitTest.java new file mode 100644 index 0000000000..531dcc5abb --- /dev/null +++ b/core-java-modules/core-java-streams-4/src/test/java/com/baeldung/streams/filteronlyoneelement/FilterUtilsUnitTest.java @@ -0,0 +1,88 @@ +package com.baeldung.streams.filteronlyoneelement; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class FilterUtilsUnitTest { + + private static final Predicate IS_STRICTLY_GREATER_THAN5 = i -> i > 5; + private static final Predicate IS_STRICTLY_GREATER_THAN4 = i -> i > 4; + private static final Predicate IS_STRICTLY_GREATER_THAN3 = i -> i > 3; + + private Stream getIntegers() { + return Stream.of(1, 2, 3, 4, 5); + } + + @Test + void givenNoElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithReduction_ThenNoneFound() { + assertTrue(FilterUtils.findUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN5) + .isEmpty()); + } + + @Test + void givenTwoElementsMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithReduction_ThenEmpty() { + assertTrue(FilterUtils.findUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN3) + .isEmpty()); + } + + @Test + void givenOnlyOneElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithReduction_ThenFindsIt() { + assertEquals(5, FilterUtils.findUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN4) + .get()); + } + + @Test + void givenNoElementMatchingPredicate_WhenGetUniqueElementMatchingPredicateWithReduction_ThenThrows() { + assertThrows(IllegalStateException.class, () -> FilterUtils.getUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN5)); + } + + @Test + void givenTwoElementsMatchingPredicate_WhenGetUniqueElementMatchingPredicateWithReduction_ThenThrows() { + assertThrows(IllegalStateException.class, () -> FilterUtils.getUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN3)); + } + + @Test + void givenOnlyOneElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithReduction_ThenGetIt() { + assertEquals(5, FilterUtils.getUniqueElementMatchingPredicate_WithReduction(getIntegers(), IS_STRICTLY_GREATER_THAN4)); + } + + @Test + void givenNoElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithCollectingAndThen_ThenEmpty() { + assertTrue(FilterUtils.findUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN5) + .isEmpty()); + } + + @Test + void givenTwoElementsMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithCollectingAndThen_ThenEmpty() { + assertTrue(FilterUtils.findUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN3) + .isEmpty()); + } + + @Test + void givenOnlyOneElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithCollectingAndThen_ThenFindsIt() { + assertEquals(5, FilterUtils.findUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN4) + .get()); + } + + @Test + void givenNoElementMatchingPredicate_WhenGetUniqueElementMatchingPredicateWithCollectingAndThen_ThenThrows() { + assertThrows(IllegalStateException.class, () -> FilterUtils.getUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN5)); + } + + @Test + void givenTwoElementsMatchingPredicate_WhenGetUniqueElementMatchingPredicateWithCollectingAndThen_ThenThrows() { + assertThrows(IllegalStateException.class, () -> FilterUtils.getUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN3)); + } + + @Test + void givenOnlyOneElementMatchingPredicate_WhenFindUniqueElementMatchingPredicateWithCollectingAndThen_ThenGetIt() { + assertEquals(5, FilterUtils.getUniqueElementMatchingPredicate_WithCollectingAndThen(getIntegers(), IS_STRICTLY_GREATER_THAN4)); + } + +}