diff --git a/java-streams-2/pom.xml b/java-streams-2/pom.xml
new file mode 100644
index 0000000000..cd89a1a80f
--- /dev/null
+++ b/java-streams-2/pom.xml
@@ -0,0 +1,39 @@
+
+
+ 4.0.0
+ com.baeldung.javastreams2
+ javastreams2
+ 1.0
+ jar
+
+
+ org.openjdk.jmh
+ jmh-core
+ 1.21
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ 1.21
+
+
+ junit
+ junit
+ 4.12
+ test
+ jar
+
+
+ org.assertj
+ assertj-core
+ 3.11.1
+ test
+
+
+ Stream Reduce
+
+ UTF-8
+ 1.8
+ 1.8
+
+
\ No newline at end of file
diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java b/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java
new file mode 100644
index 0000000000..79c557524d
--- /dev/null
+++ b/java-streams-2/src/main/java/com/baeldung/reduce/application/Application.java
@@ -0,0 +1,39 @@
+package com.baeldung.reduce.application;
+
+import com.baeldung.reduce.entities.User;
+import com.baeldung.reduce.utilities.NumberUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Application {
+
+ public static void main(String[] args) {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+ int result1 = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element);
+ System.out.println(result1);
+
+ int result2 = numbers.stream().reduce(0, Integer::sum);
+ System.out.println(result2);
+
+ List letters = Arrays.asList("a", "b", "c", "d", "e");
+ String result3 = letters.stream().reduce("", (partialString, element) -> partialString + element);
+ System.out.println(result3);
+
+ String result4 = letters.stream().reduce("", String::concat);
+ System.out.println(result4);
+
+ String result5 = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase());
+ System.out.println(result5);
+
+ List users = Arrays.asList(new User("John", 30), new User("Julie", 35));
+ int result6 = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ System.out.println(result6);
+
+ String result7 = letters.parallelStream().reduce("", String::concat);
+ System.out.println(result7);
+
+ int result8 = users.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ System.out.println(result8);
+ }
+}
diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java b/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java
new file mode 100644
index 0000000000..af4a9276a9
--- /dev/null
+++ b/java-streams-2/src/main/java/com/baeldung/reduce/benchmarks/JMHStreamReduceBenchMark.java
@@ -0,0 +1,52 @@
+package com.baeldung.reduce.benchmarks;
+
+import com.baeldung.reduce.entities.User;
+import java.util.ArrayList;
+import java.util.List;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+public class JMHStreamReduceBenchMark {
+
+ private final List userList = createUsers();
+
+ public static void main(String[] args) throws RunnerException {
+
+ Options options = new OptionsBuilder()
+ .include(JMHStreamReduceBenchMark.class.getSimpleName()).threads(1)
+ .forks(1).shouldFailOnError(true).shouldDoGC(true)
+ .jvmArgs("-server").build();
+ new Runner(options).run();
+ }
+
+ private List createUsers() {
+ List users = new ArrayList<>();
+ for (int i = 0; i <= 1000000; i++) {
+ users.add(new User("John" + i, i));
+ }
+ return users;
+ }
+
+ @Benchmark
+ public Integer executeReduceOnParallelizedStream() {
+ return this.userList
+ .parallelStream()
+ .reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ }
+
+ @Benchmark
+ public Integer executeReduceOnSequentialStream() {
+ return this.userList
+ .stream()
+ .reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ }
+}
diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java b/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java
new file mode 100644
index 0000000000..a17c6a02b6
--- /dev/null
+++ b/java-streams-2/src/main/java/com/baeldung/reduce/entities/User.java
@@ -0,0 +1,25 @@
+package com.baeldung.reduce.entities;
+
+public class User {
+
+ private final String name;
+ private final int age;
+
+ public User(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ @Override
+ public String toString() {
+ return "User{" + "name=" + name + ", age=" + age + '}';
+ }
+}
diff --git a/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java b/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java
new file mode 100644
index 0000000000..a7a4b8df29
--- /dev/null
+++ b/java-streams-2/src/main/java/com/baeldung/reduce/utilities/NumberUtils.java
@@ -0,0 +1,52 @@
+package com.baeldung.reduce.utilities;
+
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public abstract class NumberUtils {
+
+ private static final Logger LOGGER = Logger.getLogger(NumberUtils.class.getName());
+
+ public static int divideListElements(List values, Integer divider) {
+ return values.stream()
+ .reduce(0, (a, b) -> {
+ try {
+ return a / divider + b / divider;
+ } catch (ArithmeticException e) {
+ LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");
+ }
+ return 0;
+ });
+ }
+
+ public static int divideListElementsWithExtractedTryCatchBlock(List values, int divider) {
+ return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider));
+ }
+
+ public static int divideListElementsWithApplyFunctionMethod(List values, int divider) {
+ BiFunction division = (a, b) -> a / b;
+ return values.stream().reduce(0, (a, b) -> applyFunction(division, a, divider) + applyFunction(division, b, divider));
+ }
+
+ private static int divide(int value, int factor) {
+ int result = 0;
+ try {
+ result = value / factor;
+ } catch (ArithmeticException e) {
+ LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");
+ }
+ return result;
+ }
+
+ private static int applyFunction(BiFunction function, int a, int b) {
+ try {
+ return function.apply(a, b);
+ }
+ catch(Exception e) {
+ LOGGER.log(Level.INFO, "Exception thrown!");
+ }
+ return 0;
+ }
+}
diff --git a/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java b/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java
new file mode 100644
index 0000000000..564d614017
--- /dev/null
+++ b/java-streams-2/src/test/java/com/baeldung/reduce/tests/StreamReduceUnitTest.java
@@ -0,0 +1,79 @@
+package com.baeldung.reduce.tests;
+
+import com.baeldung.reduce.entities.User;
+import com.baeldung.reduce.utilities.NumberUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+
+public class StreamReduceUnitTest {
+
+ @Test
+ public void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+ int result = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element);
+ assertThat(result).isEqualTo(21);
+ }
+
+ @Test
+ public void givenIntegerList_whenReduceWithSumAccumulatorMethodReference_thenCorrect() {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+ int result = numbers.stream().reduce(0, Integer::sum);
+ assertThat(result).isEqualTo(21);
+ }
+
+ @Test
+ public void givenStringList_whenReduceWithConcatenatorAccumulatorLambda_thenCorrect() {
+ List letters = Arrays.asList("a", "b", "c", "d", "e");
+ String result = letters.stream().reduce("", (partialString, element) -> partialString + element);
+ assertThat(result).isEqualTo("abcde");
+ }
+
+ @Test
+ public void givenStringList_whenReduceWithConcatenatorAccumulatorMethodReference_thenCorrect() {
+ List letters = Arrays.asList("a", "b", "c", "d", "e");
+ String result = letters.stream().reduce("", String::concat);
+ assertThat(result).isEqualTo("abcde");
+ }
+
+ @Test
+ public void givenStringList_whenReduceWithUppercaseConcatenatorAccumulator_thenCorrect() {
+ List letters = Arrays.asList("a", "b", "c", "d", "e");
+ String result = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase());
+ assertThat(result).isEqualTo("ABCDE");
+ }
+
+ @Test
+ public void givenUserList_whenReduceWithAgeAccumulatorAndSumCombiner_thenCorrect() {
+ List users = Arrays.asList(new User("John", 30), new User("Julie", 35));
+ int result = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ assertThat(result).isEqualTo(65);
+ }
+
+ @Test
+ public void givenStringList_whenReduceWithParallelStream_thenCorrect() {
+ List letters = Arrays.asList("a", "b", "c", "d", "e");
+ String result = letters.parallelStream().reduce("", String::concat);
+ assertThat(result).isEqualTo("abcde");
+ }
+
+ @Test
+ public void givenNumberUtilsClass_whenCalledDivideListElements_thenCorrect() {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+ assertThat(NumberUtils.divideListElements(numbers, 1)).isEqualTo(21);
+ }
+
+ @Test
+ public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlock_thenCorrect() {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+ assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21);
+ }
+
+ @Test
+ public void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+ assertThat(NumberUtils.divideListElementsWithApplyFunctionMethod(numbers, 1)).isEqualTo(21);
+ }
+}