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));
+ }
+
+}