diff --git a/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/streamsvsloops/PerformanceBenchmark.java b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/streamsvsloops/PerformanceBenchmark.java new file mode 100644 index 0000000000..6c1ee9b2dd --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/main/java/com/baeldung/streams/streamsvsloops/PerformanceBenchmark.java @@ -0,0 +1,111 @@ +package com.baeldung.streams.streamsvsloops; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +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; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class PerformanceBenchmark { + + @State(Scope.Thread) + public static class MyState { + List numbers; + + @Setup(Level.Trial) + public void setUp() { + numbers = new ArrayList<>(); + for (int i = 0; i < 1_000_000; i++) { + numbers.add(i); + } + } + } + + @Benchmark + public int forLoopBenchmark(MyState state) { + int sum = 0; + for (int number : state.numbers) { + if (number % 2 == 0) { + sum = sum + (number * number); + } + } + return sum; + } + + @Benchmark + public int parallelStreamBenchMark(MyState state) { + return state.numbers.parallelStream() + .filter(number -> number % 2 == 0) + .map(number -> number * number) + .reduce(0, Integer::sum); + } + + @Benchmark + public int concurrentForLoopBenchmark(MyState state) throws InterruptedException, ExecutionException { + int numThreads = Runtime.getRuntime().availableProcessors(); + ExecutorService executorService = Executors.newFixedThreadPool(numThreads); + List> tasks = new ArrayList<>(); + int chunkSize = state.numbers.size() / numThreads; + + for (int i = 0; i < numThreads; i++) { + final int start = i * chunkSize; + final int end = (i == numThreads - 1) ? state.numbers.size() : (i + 1) * chunkSize; + tasks.add(() -> { + int sum = 0; + for (int j = start; j < end; j++) { + int number = state.numbers.get(j); + if (number % 2 == 0) { + sum = sum + (number * number); + } + } + return sum; + }); + } + + int totalSum = 0; + for (Future result : executorService.invokeAll(tasks)) { + totalSum += result.get(); + } + + executorService.shutdown(); + return totalSum; + } + + @Benchmark + public int streamBenchMark(MyState state) { + return state.numbers.stream() + .filter(number -> number % 2 == 0) + .map(number -> number * number) + .reduce(0, Integer::sum); + } + + public static void main(String[] args) throws RunnerException { + Options options = new OptionsBuilder().include(PerformanceBenchmark.class.getSimpleName()) + .build(); + new Runner(options).run(); + } +} diff --git a/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/streamsvsloops/StreamsVsLoopsUnitTest.java b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/streamsvsloops/StreamsVsLoopsUnitTest.java new file mode 100644 index 0000000000..e84fbc3da3 --- /dev/null +++ b/core-java-modules/core-java-streams-5/src/test/java/com/baeldung/streamsvsloops/StreamsVsLoopsUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.streamsvsloops; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; + +public class StreamsVsLoopsUnitTest { + + @Test + public void givenListWithFruits_whenFilterUsingStream_thenReturnedCount() { + List fruits = Arrays.asList("apple", "banana", "orange", "grape"); + long count = fruits.stream() + .filter(fruit -> fruit.length() > 5) + .count(); + assertEquals(2, count); + } + + @Test + public void givenListWithFruits_whenFilterUsingForLoop_thenReturnedCount() { + List fruits = Arrays.asList("apple", "banana", "orange", "grape"); + long count = 0; for (String fruit : fruits) { + if (fruit.length() > 5) { + count++; + } + } + assertEquals(2, count); + } + + @Test + public void givenListWithFruits_whenApplyUppercase_thenNewListGenerated() { + List desiredArray = new ArrayList<>(Arrays.asList("APPLE", "BANANA", "ORANGE")); + List fruits = new ArrayList<>(Arrays.asList("apple", "banana", "orange")); + List upperCaseFruits = fruits.stream() + .map(fruit -> fruit.toUpperCase()) + .collect(Collectors.toList()); + assertThat(desiredArray, is(upperCaseFruits)); + } + + @Test + public void givenListWithFruits_whenApplyUppercase_elementsAreUpdated() { + List desiredArray = new ArrayList<>(Arrays.asList("APPLE", "BANANA", "ORANGE")); + List fruits = new ArrayList<>(Arrays.asList("apple", "banana", "orange")); + for (int i = 0; i < fruits.size(); i++) { + fruits.set(i, fruits.get(i).toUpperCase()); + } + assertThat(desiredArray, is(fruits)); + } +}