[JAVA-12051] Moved code to core-java-streams-simple for ebook (#14889)

This commit is contained in:
panos-kakos
2023-10-13 14:41:35 +03:00
committed by GitHub
parent ff826f0d08
commit ee98df03f4
38 changed files with 200 additions and 76 deletions
@@ -0,0 +1,14 @@
## Java Streams Ebook
This module contains articles about Streams that are part of the Java Streams Ebook.
### Relevant Articles
- [Introduction to Java 8 Streams](https://www.baeldung.com/java-8-streams-introduction)
- [Guide to Java 8s Collectors](https://www.baeldung.com/java-8-collectors)
- [Java Stream Filter with Lambda Expression](https://www.baeldung.com/java-stream-filter-lambda)
- [Working With Maps Using Streams](https://www.baeldung.com/java-maps-streams)
- [The Difference Between map() and flatMap()](https://www.baeldung.com/java-difference-map-and-flatmap)
- [When to Use a Parallel Stream in Java](https://www.baeldung.com/java-when-to-use-parallel-stream)
- [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector)
- [Guide to Stream.reduce()](https://www.baeldung.com/java-stream-reduce)
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>core-java-streams-simple</artifactId>
<name>core-java-streams-simple</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.core-java-modules</groupId>
<artifactId>core-java-modules</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.pivovarit</groupId>
<artifactId>throwing-function</artifactId>
<version>${throwing-function.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
</dependencies>
<build>
<finalName>core-java-streams-simple</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
<properties>
<throwing-function.version>1.5.1</throwing-function.version>
<maven.compiler.source.version>17</maven.compiler.source.version>
<maven.compiler.target.version>17</maven.compiler.target.version>
<maven.compiler.release>17</maven.compiler.release>
</properties>
</project>
@@ -0,0 +1,56 @@
package com.baeldung.streams.filter;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class Customer {
private String name;
private int points;
private String profilePhotoUrl;
public Customer(String name, int points) {
this(name, points, "");
}
public Customer(String name, int points, String profilePhotoUrl) {
this.name = name;
this.points = points;
this.profilePhotoUrl = profilePhotoUrl;
}
public String getName() {
return name;
}
public int getPoints() {
return points;
}
public boolean hasOver(int points) {
return this.points > points;
}
public boolean hasOverHundredPoints() {
return this.points > 100;
}
public boolean hasValidProfilePhoto() throws IOException {
URL url = new URL(this.profilePhotoUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
}
public boolean hasValidProfilePhotoWithoutCheckedException() {
try {
URL url = new URL(this.profilePhotoUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,43 @@
package com.baeldung.streams.groupingby;
import java.util.IntSummaryStatistics;
public class BlogPost {
private String title;
private String author;
private BlogPostType type;
private int likes;
record AuthPostTypesLikes(String author, BlogPostType type, int likes) {};
record PostCountTitlesLikesStats(long postCount, String titles, IntSummaryStatistics likesStats){};
record TitlesBoundedSumOfLikes(String titles, int boundedSumOfLikes) {};
public BlogPost(String title, String author, BlogPostType type, int likes) {
this.title = title;
this.author = author;
this.type = type;
this.likes = likes;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
public BlogPostType getType() {
return type;
}
public int getLikes() {
return likes;
}
@Override
public String toString() {
return "BlogPost{" + "title='" + title + '\'' + ", type=" + type + ", likes=" + likes + '}';
}
}
@@ -0,0 +1,5 @@
package com.baeldung.streams.groupingby;
public enum BlogPostType {
NEWS, REVIEW, GUIDE
}
@@ -0,0 +1,41 @@
package com.baeldung.streams.groupingby;
import java.util.Objects;
public class Tuple {
private final BlogPostType type;
private final String author;
public Tuple(BlogPostType type, String author) {
this.type = type;
this.author = author;
}
public BlogPostType getType() {
return type;
}
public String getAuthor() {
return author;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Tuple tuple = (Tuple) o;
return type == tuple.type && author.equals(tuple.author);
}
@Override
public int hashCode() {
return Objects.hash(type, author);
}
@Override
public String toString() {
return "Tuple{" + "type=" + type + ", author='" + author + '\'' + '}';
}
}
@@ -0,0 +1,9 @@
package com.baeldung.streams.parallel;
public class BenchmarkRunner {
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
}
@@ -0,0 +1,54 @@
package com.baeldung.streams.parallel;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class DifferentSourceSplitting {
private static final List<Integer> arrayListOfNumbers = new ArrayList<>();
private static final List<Integer> linkedListOfNumbers = new LinkedList<>();
static {
IntStream.rangeClosed(1, 1_000_000).forEach(i -> {
arrayListOfNumbers.add(i);
linkedListOfNumbers.add(i);
});
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void differentSourceArrayListSequential() {
arrayListOfNumbers.stream().reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void differentSourceArrayListParallel() {
arrayListOfNumbers.parallelStream().reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void differentSourceLinkedListSequential() {
linkedListOfNumbers.stream().reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void differentSourceLinkedListParallel() {
linkedListOfNumbers.parallelStream().reduce(0, Integer::sum);
}
}
@@ -0,0 +1,60 @@
package com.baeldung.streams.parallel;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
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.TearDown;
@State(Scope.Benchmark)
public class FileSearchCost {
private final static String FILE_NAME = "src/main/resources/Test";
@Setup(Level.Trial)
public void setup() throws IOException {
for (int i = 0; i < 1500; i++) {
File targetFile = new File(FILE_NAME + i);
FileUtils.writeStringToFile(targetFile, "Test", "UTF8");
}
}
@TearDown(Level.Trial)
public void tearDown() {
for (int i = 0; i < 1500; i++) {
File fileToDelete = new File(FILE_NAME + i);
fileToDelete.delete();
}
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void textFileSearchSequential() throws IOException {
Files.walk(Paths.get("src/main/resources/")).map(Path::normalize).filter(Files::isRegularFile)
.filter(path -> path.getFileName().toString().endsWith(".txt")).collect(Collectors.toList());
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void textFileSearchParallel() throws IOException {
Files.walk(Paths.get("src/main/resources/")).parallel().map(Path::normalize).filter(Files::isRegularFile)
.filter(path -> path.getFileName().toString().endsWith(".txt")).collect(Collectors.toList());
}
}
@@ -0,0 +1,52 @@
package com.baeldung.streams.parallel;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class MemoryLocalityCosts {
private static final int[] intArray = new int[1_000_000];
private static final Integer[] integerArray = new Integer[1_000_000];
static {
IntStream.rangeClosed(1, 1_000_000).forEach(i -> {
intArray[i-1] = i;
integerArray[i-1] = i;
});
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void localityIntArraySequential() {
Arrays.stream(intArray).reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void localityIntArrayParallel() {
Arrays.stream(intArray).parallel().reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void localityIntegerArraySequential() {
Arrays.stream(integerArray).reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void localityIntegerArrayParallel() {
Arrays.stream(integerArray).parallel().reduce(0, Integer::sum);
}
}
@@ -0,0 +1,52 @@
package com.baeldung.streams.parallel;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class MergingCosts {
private static final List<Integer> arrayListOfNumbers = new ArrayList<>();
static {
IntStream.rangeClosed(1, 1_000_000).forEach(i -> {
arrayListOfNumbers.add(i);
});
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void mergingCostsSumSequential() {
arrayListOfNumbers.stream().reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void mergingCostsSumParallel() {
arrayListOfNumbers.stream().parallel().reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void mergingCostsGroupingSequential() {
arrayListOfNumbers.stream().collect(Collectors.toSet());
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void mergingCostsGroupingParallel() {
arrayListOfNumbers.stream().parallel().collect(Collectors.toSet());
}
}
@@ -0,0 +1,15 @@
package com.baeldung.streams.parallel;
import java.util.Arrays;
import java.util.List;
public class ParallelStream {
public static void main(String[] args) {
List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
listOfNumbers.parallelStream().forEach(number ->
System.out.println(number + " " + Thread.currentThread().getName())
);
}
}
@@ -0,0 +1,15 @@
package com.baeldung.streams.parallel;
import java.util.Arrays;
import java.util.List;
public class SequentialStream {
public static void main(String[] args) {
List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
listOfNumbers.stream().forEach(number ->
System.out.println(number + " " + Thread.currentThread().getName())
);
}
}
@@ -0,0 +1,27 @@
package com.baeldung.streams.parallel;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class SplittingCosts {
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void sourceSplittingIntStreamSequential() {
IntStream.rangeClosed(1, 100).reduce(0, Integer::sum);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public static void sourceSplittingIntStreamParallel() {
IntStream.rangeClosed(1, 100).parallel().reduce(0, Integer::sum);
}
}
@@ -0,0 +1,38 @@
package com.baeldung.streams.reduce.application;
import com.baeldung.streams.reduce.entities.User;
import java.util.Arrays;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<Integer> 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<String> 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<User> 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);
}
}
@@ -0,0 +1,52 @@
package com.baeldung.streams.reduce.benchmarks;
import com.baeldung.streams.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<User> 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<User> createUsers() {
List<User> 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);
}
}
@@ -0,0 +1,39 @@
package com.baeldung.streams.reduce.entities;
import java.util.ArrayList;
import java.util.List;
public class Rating {
double points;
List<Review> reviews = new ArrayList<>();
public Rating() {}
public void add(Review review) {
reviews.add(review);
computeRating();
}
private double computeRating() {
double totalPoints = reviews.stream().map(Review::getPoints).reduce(0, Integer::sum);
this.points = totalPoints / reviews.size();
return this.points;
}
public static Rating average(Rating r1, Rating r2) {
Rating combined = new Rating();
combined.reviews = new ArrayList<>(r1.reviews);
combined.reviews.addAll(r2.reviews);
combined.computeRating();
return combined;
}
public double getPoints() {
return points;
}
public List<Review> getReviews() {
return reviews;
}
}
@@ -0,0 +1,28 @@
package com.baeldung.streams.reduce.entities;
public class Review {
int points;
String review;
public Review(int points, String review) {
this.points = points;
this.review = review;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
public String getReview() {
return review;
}
public void setReview(String review) {
this.review = review;
}
}
@@ -0,0 +1,25 @@
package com.baeldung.streams.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 + '}';
}
}
@@ -0,0 +1,52 @@
package com.baeldung.streams.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<Integer> 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<Integer> values, int divider) {
return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider));
}
public static int divideListElementsWithApplyFunctionMethod(List<Integer> values, int divider) {
BiFunction<Integer, Integer, Integer> 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<Integer, Integer, Integer> function, int a, int b) {
try {
return function.apply(a, b);
}
catch(Exception e) {
LOGGER.log(Level.INFO, "Exception thrown!");
}
return 0;
}
}
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,13 @@
package com.baeldung.streams;
import java.util.Arrays;
import java.util.List;
public class Detail {
private static final List<String> PARTS = Arrays.asList("turbine", "pump");
public List<String> getParts() {
return PARTS;
}
}
@@ -0,0 +1,104 @@
package com.baeldung.streams;
import org.junit.Before;
import org.junit.Test;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.Assert.*;
public class Java8StreamsUnitTest {
private List<String> list;
@Before
public void init() {
list = new ArrayList<>();
list.add("One");
list.add("OneAndOnly");
list.add("Derek");
list.add("Change");
list.add("factory");
list.add("justBefore");
list.add("Italy");
list.add("Italy");
list.add("Thursday");
list.add("");
list.add("");
}
@Test
public void checkStreamCount_whenCreating_givenDifferentSources() {
String[] arr = new String[] { "a", "b", "c" };
Stream<String> streamArr = Arrays.stream(arr);
assertEquals(streamArr.count(), 3);
Stream<String> streamOf = Stream.of("a", "b", "c");
assertEquals(streamOf.count(), 3);
long count = list.stream().distinct().count();
assertEquals(count, 9);
}
@Test
public void checkStreamCount_whenOperationFilter_thanCorrect() {
Stream<String> streamFilter = list.stream().filter(element -> element.isEmpty());
assertEquals(streamFilter.count(), 2);
}
@Test
public void checkStreamCount_whenOperationMap_thanCorrect() {
List<String> uris = new ArrayList<>();
uris.add("C:\\My.txt");
Stream<Path> streamMap = uris.stream().map(uri -> Paths.get(uri));
assertEquals(streamMap.count(), 1);
List<Detail> details = new ArrayList<>();
details.add(new Detail());
details.add(new Detail());
Stream<String> streamFlatMap = details.stream().flatMap(detail -> detail.getParts().stream());
assertEquals(streamFlatMap.count(), 4);
}
@Test
public void checkStreamCount_whenOperationMatch_thenCorrect() {
boolean isValid = list.stream().anyMatch(element -> element.contains("h"));
boolean isValidOne = list.stream().allMatch(element -> element.contains("h"));
boolean isValidTwo = list.stream().noneMatch(element -> element.contains("h"));
assertTrue(isValid);
assertFalse(isValidOne);
assertFalse(isValidTwo);
}
@Test
public void checkStreamReducedValue_whenOperationReduce_thenCorrect() {
List<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(1);
integers.add(1);
Integer reduced = integers.stream().reduce(23, (a, b) -> a + b);
assertTrue(reduced == 26);
}
@Test
public void checkStreamContains_whenOperationCollect_thenCorrect() {
List<String> resultList = list.stream().map(element -> element.toUpperCase()).collect(Collectors.toList());
assertEquals(resultList.size(), list.size());
assertTrue(resultList.contains(""));
}
@Test
public void checkParallelStream_whenDoWork() {
list.parallelStream().forEach(element -> doWork(element));
}
private void doWork(String string) {
assertTrue(true); // just imitate an amount of work
}
}
@@ -0,0 +1,237 @@
package com.baeldung.streams.collectors;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.junit.Test;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.stream.Collectors.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class Java8CollectorsUnitTest {
private final List<String> givenList = Arrays.asList("a", "bb", "ccc", "dd");
private final List<String> listWithDuplicates = Arrays.asList("a", "bb", "c", "d", "bb");
@Test
public void whenCollectingToList_shouldCollectToList() throws Exception {
final List<String> result = givenList.stream().collect(toList());
assertThat(result).containsAll(givenList);
}
@Test
public void whenCollectingToUnmodifiableList_shouldCollectToUnmodifiableList() {
final List<String> result = givenList.stream().collect(toUnmodifiableList());
assertThatThrownBy(() -> result.add("foo"))
.isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void whenCollectingToSet_shouldCollectToSet() throws Exception {
final Set<String> result = givenList.stream().collect(toSet());
assertThat(result).containsAll(givenList);
}
@Test
public void whenCollectingToUnmodifiableSet_shouldCollectToUnmodifiableSet() {
final Set<String> result = givenList.stream().collect(toUnmodifiableSet());
assertThatThrownBy(() -> result.add("foo"))
.isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void givenContainsDuplicateElements_whenCollectingToSet_shouldAddDuplicateElementsOnlyOnce() throws Exception {
final Set<String> result = listWithDuplicates.stream().collect(toSet());
assertThat(result).hasSize(4);
}
@Test
public void whenCollectingToCollection_shouldCollectToCollection() throws Exception {
final List<String> result = givenList.stream().collect(toCollection(LinkedList::new));
assertThat(result).containsAll(givenList).isInstanceOf(LinkedList.class);
}
@Test
public void whenCollectingToImmutableCollection_shouldThrowException() throws Exception {
assertThatThrownBy(() -> {
givenList.stream().collect(toCollection(ImmutableList::of));
}).isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void whenCollectingToMap_shouldCollectToMap() throws Exception {
final Map<String, Integer> result = givenList.stream().collect(toMap(Function.identity(), String::length));
assertThat(result).containsEntry("a", 1).containsEntry("bb", 2).containsEntry("ccc", 3).containsEntry("dd", 2);
}
@Test
public void whenCollectingToUnmodifiableMap_shouldCollectToUnmodifiableMap() {
final Map<String, Integer> result = givenList.stream()
.collect(toUnmodifiableMap(Function.identity(), String::length));
assertThatThrownBy(() -> result.put("foo", 3))
.isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void whenCollectingToMapwWithDuplicates_shouldCollectToMapMergingTheIdenticalItems() throws Exception {
final Map<String, Integer> result = listWithDuplicates.stream().collect(
toMap(
Function.identity(),
String::length,
(item, identicalItem) -> item
)
);
assertThat(result).containsEntry("a", 1).containsEntry("bb", 2).containsEntry("c", 1).containsEntry("d", 1);
}
@Test
public void givenContainsDuplicateElements_whenCollectingToMap_shouldThrowException() throws Exception {
assertThatThrownBy(() -> {
listWithDuplicates.stream().collect(toMap(Function.identity(), String::length));
}).isInstanceOf(IllegalStateException.class);
}
@Test
public void whenCollectingAndThen_shouldCollect() throws Exception {
final List<String> result = givenList.stream().collect(collectingAndThen(toList(), ImmutableList::copyOf));
assertThat(result).containsAll(givenList).isInstanceOf(ImmutableList.class);
}
@Test
public void whenJoining_shouldJoin() throws Exception {
final String result = givenList.stream().collect(joining());
assertThat(result).isEqualTo("abbcccdd");
}
@Test
public void whenJoiningWithSeparator_shouldJoinWithSeparator() throws Exception {
final String result = givenList.stream().collect(joining(" "));
assertThat(result).isEqualTo("a bb ccc dd");
}
@Test
public void whenJoiningWithSeparatorAndPrefixAndPostfix_shouldJoinWithSeparatorPrePost() throws Exception {
final String result = givenList.stream().collect(joining(" ", "PRE-", "-POST"));
assertThat(result).isEqualTo("PRE-a bb ccc dd-POST");
}
@Test
public void whenPartitioningBy_shouldPartition() throws Exception {
final Map<Boolean, List<String>> result = givenList.stream().collect(partitioningBy(s -> s.length() > 2));
assertThat(result).containsKeys(true, false).satisfies(booleanListMap -> {
assertThat(booleanListMap.get(true)).contains("ccc");
assertThat(booleanListMap.get(false)).contains("a", "bb", "dd");
});
}
@Test
public void whenCounting_shouldCount() throws Exception {
final Long result = givenList.stream().collect(counting());
assertThat(result).isEqualTo(4);
}
@Test
public void whenSummarizing_shouldSummarize() throws Exception {
final DoubleSummaryStatistics result = givenList.stream().collect(summarizingDouble(String::length));
assertThat(result.getAverage()).isEqualTo(2);
assertThat(result.getCount()).isEqualTo(4);
assertThat(result.getMax()).isEqualTo(3);
assertThat(result.getMin()).isEqualTo(1);
assertThat(result.getSum()).isEqualTo(8);
}
@Test
public void whenAveraging_shouldAverage() throws Exception {
final Double result = givenList.stream().collect(averagingDouble(String::length));
assertThat(result).isEqualTo(2);
}
@Test
public void whenSumming_shouldSum() throws Exception {
final Double result = givenList.stream().filter(i -> true).collect(summingDouble(String::length));
assertThat(result).isEqualTo(8);
}
@Test
public void whenMaxingBy_shouldMaxBy() throws Exception {
final Optional<String> result = givenList.stream().collect(maxBy(Comparator.naturalOrder()));
assertThat(result).isPresent().hasValue("dd");
}
@Test
public void whenGroupingBy_shouldGroupBy() throws Exception {
final Map<Integer, Set<String>> result = givenList.stream().collect(groupingBy(String::length, toSet()));
assertThat(result).containsEntry(1, newHashSet("a")).containsEntry(2, newHashSet("bb", "dd")).containsEntry(3, newHashSet("ccc"));
}
@Test
public void whenCreatingCustomCollector_shouldCollect() throws Exception {
final ImmutableSet<String> result = givenList.stream().collect(toImmutableSet());
assertThat(result).isInstanceOf(ImmutableSet.class).contains("a", "bb", "ccc", "dd");
}
private static <T> ImmutableSetCollector<T> toImmutableSet() {
return new ImmutableSetCollector<>();
}
private static class ImmutableSetCollector<T> implements Collector<T, ImmutableSet.Builder<T>, ImmutableSet<T>> {
@Override
public Supplier<ImmutableSet.Builder<T>> supplier() {
return ImmutableSet::builder;
}
@Override
public BiConsumer<ImmutableSet.Builder<T>, T> accumulator() {
return ImmutableSet.Builder::add;
}
@Override
public BinaryOperator<ImmutableSet.Builder<T>> combiner() {
return (left, right) -> left.addAll(right.build());
}
@Override
public Function<ImmutableSet.Builder<T>, ImmutableSet<T>> finisher() {
return ImmutableSet.Builder::build;
}
@Override
public Set<Characteristics> characteristics() {
return Sets.immutableEnumSet(Characteristics.UNORDERED);
}
}
}
@@ -0,0 +1,159 @@
package com.baeldung.streams.filter;
import org.junit.jupiter.api.Test;
import com.pivovarit.function.ThrowingPredicate;
import com.pivovarit.function.exception.WrappedException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
class StreamFilterUnitTest {
@Test
void givenListOfCustomers_whenFilterByPoints_thenGetTwo() {
Customer john = new Customer("John P.", 15);
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1);
List<Customer> customers = Arrays.asList(john, sarah, charles, mary);
List<Customer> customersWithMoreThan100Points = customers
.stream()
.filter(c -> c.getPoints() > 100)
.collect(Collectors.toList());
assertThat(customersWithMoreThan100Points).hasSize(2);
assertThat(customersWithMoreThan100Points).contains(sarah, charles);
}
@Test
public void givenListOfCustomers_whenFilterByPointsAndName_thenGetOne() {
Customer john = new Customer("John P.", 15);
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1);
List<Customer> customers = Arrays.asList(john, sarah, charles, mary);
List<Customer> charlesWithMoreThan100Points = customers
.stream()
.filter(c -> c.getPoints() > 100 && c
.getName()
.startsWith("Charles"))
.collect(Collectors.toList());
assertThat(charlesWithMoreThan100Points).hasSize(1);
assertThat(charlesWithMoreThan100Points).contains(charles);
}
@Test
void givenListOfCustomers_whenFilterByMethodReference_thenGetTwo() {
Customer john = new Customer("John P.", 15);
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1);
List<Customer> customers = Arrays.asList(john, sarah, charles, mary);
List<Customer> customersWithMoreThan100Points = customers
.stream()
.filter(Customer::hasOverHundredPoints)
.collect(Collectors.toList());
assertThat(customersWithMoreThan100Points).hasSize(2);
assertThat(customersWithMoreThan100Points).contains(sarah, charles);
}
@Test
void givenListOfCustomersWithOptional_whenFilterBy100Points_thenGetTwo() {
Optional<Customer> john = Optional.of(new Customer("John P.", 15));
Optional<Customer> sarah = Optional.of(new Customer("Sarah M.", 200));
Optional<Customer> mary = Optional.of(new Customer("Mary T.", 300));
List<Optional<Customer>> customers = Arrays.asList(john, sarah, Optional.empty(), mary, Optional.empty());
List<Customer> customersWithMoreThan100Points = customers
.stream()
.flatMap(c -> c
.map(Stream::of)
.orElseGet(Stream::empty))
.filter(Customer::hasOverHundredPoints)
.collect(Collectors.toList());
assertThat(customersWithMoreThan100Points).hasSize(2);
assertThat(customersWithMoreThan100Points).contains(sarah.get(), mary.get());
}
@Test
void givenListOfCustomers_whenFilterWithCustomHandling_thenThrowException() {
Customer john = new Customer("John P.", 15, "https://images.unsplash.com/photo-1543320485-d0d5a49c2b2e");
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1, "https://images.unsplash.com/photo-1543297057-25167dfc180e");
List<Customer> customers = Arrays.asList(john, sarah, charles, mary);
assertThatThrownBy(() -> customers
.stream()
.filter(Customer::hasValidProfilePhotoWithoutCheckedException)
.count()).isInstanceOf(RuntimeException.class);
}
@Test
void givenListOfCustomers_whenFilterWithThrowingFunction_thenThrowException() {
Customer john = new Customer("John P.", 15, "https://images.unsplash.com/photo-1543320485-d0d5a49c2b2e");
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1, "https://images.unsplash.com/photo-1543297057-25167dfc180e");
List<Customer> customers = Arrays.asList(john, sarah, charles, mary);
assertThatThrownBy(() -> customers
.stream()
.filter((ThrowingPredicate.unchecked(Customer::hasValidProfilePhoto)))
.collect(Collectors.toList())).isInstanceOf(WrappedException.class);
}
@Test
public void givenListOfCustomers_whenFilterWithTryCatch_thenGetTwo() {
Customer john = new Customer("John P.", 15, "https://images.unsplash.com/photo-1543320485-d0d5a49c2b2e");
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1, "https://images.unsplash.com/photo-1543297057-25167dfc180e");
List<Customer> customers = Arrays.asList(john, sarah, charles, mary);
List<Customer> customersWithValidProfilePhoto = customers
.stream()
.filter(c -> {
try {
return c.hasValidProfilePhoto();
} catch (IOException e) {
//handle exception
}
return false;
})
.collect(Collectors.toList());
assertThat(customersWithValidProfilePhoto).hasSize(2);
assertThat(customersWithValidProfilePhoto).contains(john, mary);
}
@Test
public void givenListOfCustomers_whenFilterWithTryCatchAndRuntime_thenThrowException() {
List<Customer> customers = Arrays.asList(new Customer("John P.", 15, "https://images.unsplash.com/photo-1543320485-d0d5a49c2b2e"), new Customer("Sarah M.", 200), new Customer("Charles B.", 150),
new Customer("Mary T.", 1, "https://images.unsplash.com/photo-1543297057-25167dfc180e"));
assertThatThrownBy(() -> customers
.stream()
.filter(c -> {
try {
return c.hasValidProfilePhoto();
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList())).isInstanceOf(RuntimeException.class);
}
}
@@ -0,0 +1,51 @@
package com.baeldung.streams.flatmap.map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
class Java8MapAndFlatMapUnitTest {
@Test
void givenStream_whenCalledMap_thenProduceList() {
List<String> myList = Stream.of("a", "b")
.map(String::toUpperCase)
.collect(Collectors.toList());
assertEquals(asList("A", "B"), myList);
}
@Test
void givenStream_whenCalledFlatMap_thenProduceFlattenedList() {
List<List<String>> list = Arrays.asList(Arrays.asList("a"), Arrays.asList("b"));
System.out.println(list);
System.out.println(list.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList()));
}
@Test
void givenOptional_whenCalledMap_thenProduceOptional() {
Optional<String> s = Optional.of("test");
assertEquals(Optional.of("TEST"), s.map(String::toUpperCase));
}
@Test
void givenOptional_whenCalledFlatMap_thenProduceFlattenedOptional() {
assertEquals(Optional.of(Optional.of("STRING")), Optional.of("string")
.map(s -> Optional.of("STRING")));
assertEquals(Optional.of("STRING"), Optional.of("string")
.flatMap(s -> Optional.of("STRING")));
}
}
@@ -0,0 +1,302 @@
package com.baeldung.streams.groupingby;
import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.averagingInt;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.groupingByConcurrent;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.summarizingInt;
import static java.util.stream.Collectors.summingInt;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.offset;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Test;
class JavaGroupingByCollectorUnitTest {
private static final List<BlogPost> posts = Arrays.asList(new BlogPost("News item 1", "Author 1", BlogPostType.NEWS, 15), new BlogPost("Tech review 1", "Author 2", BlogPostType.REVIEW, 5),
new BlogPost("Programming guide", "Author 1", BlogPostType.GUIDE, 20), new BlogPost("News item 2", "Author 2", BlogPostType.NEWS, 35), new BlogPost("Tech review 2", "Author 1", BlogPostType.REVIEW, 15));
@Test
void givenAListOfPosts_whenGroupedByType_thenGetAMapBetweenTypeAndPosts() {
Map<BlogPostType, List<BlogPost>> postsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType));
assertEquals(2, postsPerType.get(BlogPostType.NEWS)
.size());
assertEquals(1, postsPerType.get(BlogPostType.GUIDE)
.size());
assertEquals(2, postsPerType.get(BlogPostType.REVIEW)
.size());
}
@Test
void givenAListOfPosts_whenGroupedByTypeAndTheirTitlesAreJoinedInAString_thenGetAMapBetweenTypeAndCsvTitles() {
Map<BlogPostType, String> postsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, mapping(BlogPost::getTitle, joining(", ", "Post titles: [", "]"))));
assertEquals("Post titles: [News item 1, News item 2]", postsPerType.get(BlogPostType.NEWS));
assertEquals("Post titles: [Programming guide]", postsPerType.get(BlogPostType.GUIDE));
assertEquals("Post titles: [Tech review 1, Tech review 2]", postsPerType.get(BlogPostType.REVIEW));
}
@Test
void givenAListOfPosts_whenGroupedByTypeAndSumTheLikes_thenGetAMapBetweenTypeAndPostLikes() {
Map<BlogPostType, Integer> likesPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, summingInt(BlogPost::getLikes)));
assertEquals(50, likesPerType.get(BlogPostType.NEWS)
.intValue());
assertEquals(20, likesPerType.get(BlogPostType.REVIEW)
.intValue());
assertEquals(20, likesPerType.get(BlogPostType.GUIDE)
.intValue());
}
@Test
void givenAListOfPosts_whenGroupedByTypeInAnEnumMap_thenGetAnEnumMapBetweenTypeAndPosts() {
EnumMap<BlogPostType, List<BlogPost>> postsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, () -> new EnumMap<>(BlogPostType.class), toList()));
assertEquals(2, postsPerType.get(BlogPostType.NEWS)
.size());
assertEquals(1, postsPerType.get(BlogPostType.GUIDE)
.size());
assertEquals(2, postsPerType.get(BlogPostType.REVIEW)
.size());
}
@Test
void givenAListOfPosts_whenGroupedByTypeInSets_thenGetAMapBetweenTypesAndSetsOfPosts() {
Map<BlogPostType, Set<BlogPost>> postsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, toSet()));
assertEquals(2, postsPerType.get(BlogPostType.NEWS)
.size());
assertEquals(1, postsPerType.get(BlogPostType.GUIDE)
.size());
assertEquals(2, postsPerType.get(BlogPostType.REVIEW)
.size());
}
@Test
void givenAListOfPosts_whenGroupedByTypeConcurrently_thenGetAMapBetweenTypeAndPosts() {
ConcurrentMap<BlogPostType, List<BlogPost>> postsPerType = posts.parallelStream()
.collect(groupingByConcurrent(BlogPost::getType));
assertEquals(2, postsPerType.get(BlogPostType.NEWS)
.size());
assertEquals(1, postsPerType.get(BlogPostType.GUIDE)
.size());
assertEquals(2, postsPerType.get(BlogPostType.REVIEW)
.size());
}
@Test
void givenAListOfPosts_whenGroupedByTypeAndAveragingLikes_thenGetAMapBetweenTypeAndAverageNumberOfLikes() {
Map<BlogPostType, Double> averageLikesPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, averagingInt(BlogPost::getLikes)));
assertEquals(25, averageLikesPerType.get(BlogPostType.NEWS)
.intValue());
assertEquals(20, averageLikesPerType.get(BlogPostType.GUIDE)
.intValue());
assertEquals(10, averageLikesPerType.get(BlogPostType.REVIEW)
.intValue());
}
@Test
void givenAListOfPosts_whenGroupedByTypeAndCounted_thenGetAMapBetweenTypeAndNumberOfPosts() {
Map<BlogPostType, Long> numberOfPostsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, counting()));
assertEquals(2, numberOfPostsPerType.get(BlogPostType.NEWS)
.intValue());
assertEquals(1, numberOfPostsPerType.get(BlogPostType.GUIDE)
.intValue());
assertEquals(2, numberOfPostsPerType.get(BlogPostType.REVIEW)
.intValue());
}
@Test
void givenAListOfPosts_whenGroupedByTypeAndMaxingLikes_thenGetAMapBetweenTypeAndMaximumNumberOfLikes() {
Map<BlogPostType, Optional<BlogPost>> maxLikesPerPostType = posts.stream()
.collect(groupingBy(BlogPost::getType, maxBy(comparingInt(BlogPost::getLikes))));
assertTrue(maxLikesPerPostType.get(BlogPostType.NEWS)
.isPresent());
assertEquals(35, maxLikesPerPostType.get(BlogPostType.NEWS)
.get()
.getLikes());
assertTrue(maxLikesPerPostType.get(BlogPostType.GUIDE)
.isPresent());
assertEquals(20, maxLikesPerPostType.get(BlogPostType.GUIDE)
.get()
.getLikes());
assertTrue(maxLikesPerPostType.get(BlogPostType.REVIEW)
.isPresent());
assertEquals(15, maxLikesPerPostType.get(BlogPostType.REVIEW)
.get()
.getLikes());
}
@Test
void givenAListOfPosts_whenGroupedByAuthorAndThenByType_thenGetAMapBetweenAuthorAndMapsBetweenTypeAndBlogPosts() {
Map<String, Map<BlogPostType, List<BlogPost>>> map = posts.stream()
.collect(groupingBy(BlogPost::getAuthor, groupingBy(BlogPost::getType)));
assertEquals(1, map.get("Author 1")
.get(BlogPostType.NEWS)
.size());
assertEquals(1, map.get("Author 1")
.get(BlogPostType.GUIDE)
.size());
assertEquals(1, map.get("Author 1")
.get(BlogPostType.REVIEW)
.size());
assertEquals(1, map.get("Author 2")
.get(BlogPostType.NEWS)
.size());
assertEquals(1, map.get("Author 2")
.get(BlogPostType.REVIEW)
.size());
assertNull(map.get("Author 2")
.get(BlogPostType.GUIDE));
}
@Test
void givenAListOfPosts_whenGroupedByTypeAndSummarizingLikes_thenGetAMapBetweenTypeAndSummary() {
Map<BlogPostType, IntSummaryStatistics> likeStatisticsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, summarizingInt(BlogPost::getLikes)));
IntSummaryStatistics newsLikeStatistics = likeStatisticsPerType.get(BlogPostType.NEWS);
assertEquals(2, newsLikeStatistics.getCount());
assertEquals(50, newsLikeStatistics.getSum());
assertEquals(25.0, newsLikeStatistics.getAverage(), 0.001);
assertEquals(35, newsLikeStatistics.getMax());
assertEquals(15, newsLikeStatistics.getMin());
}
@Test
void givenAListOfPosts_whenGroupedByComplexMapPairKeyType_thenGetAMapBetweenPairAndList() {
Map<Pair<BlogPostType, String>, List<BlogPost>> postsPerTypeAndAuthor = posts.stream()
.collect(groupingBy(post -> new ImmutablePair<>(post.getType(), post.getAuthor())));
List<BlogPost> result = postsPerTypeAndAuthor.get(new ImmutablePair<>(BlogPostType.GUIDE, "Author 1"));
assertThat(result.size()).isEqualTo(1);
BlogPost blogPost = result.get(0);
assertThat(blogPost.getTitle()).isEqualTo("Programming guide");
assertThat(blogPost.getType()).isEqualTo(BlogPostType.GUIDE);
assertThat(blogPost.getAuthor()).isEqualTo("Author 1");
}
@Test
public void givenAListOfPosts_whenGroupedByComplexMapKeyType_thenGetAMapBetweenTupleAndList() {
Map<Tuple, List<BlogPost>> postsPerTypeAndAuthor = posts.stream()
.collect(groupingBy(post -> new Tuple(post.getType(), post.getAuthor())));
List<BlogPost> result = postsPerTypeAndAuthor.get(new Tuple(BlogPostType.GUIDE, "Author 1"));
assertThat(result.size()).isEqualTo(1);
BlogPost blogPost = result.get(0);
assertThat(blogPost.getTitle()).isEqualTo("Programming guide");
assertThat(blogPost.getType()).isEqualTo(BlogPostType.GUIDE);
assertThat(blogPost.getAuthor()).isEqualTo("Author 1");
}
@Test
public void givenAListOfPosts_whenGroupedByRecord_thenGetAMapBetweenRecordAndList() {
Map<BlogPost.AuthPostTypesLikes, List<BlogPost>> postsPerTypeAndAuthor = posts.stream()
.collect(groupingBy(post -> new BlogPost.AuthPostTypesLikes(post.getAuthor(), post.getType(), post.getLikes())));
List<BlogPost> result = postsPerTypeAndAuthor.get(new BlogPost.AuthPostTypesLikes("Author 1", BlogPostType.GUIDE, 20));
assertThat(result.size()).isEqualTo(1);
BlogPost blogPost = result.get(0);
assertThat(blogPost.getTitle()).isEqualTo("Programming guide");
assertThat(blogPost.getType()).isEqualTo(BlogPostType.GUIDE);
assertThat(blogPost.getAuthor()).isEqualTo("Author 1");
assertThat(blogPost.getLikes()).isEqualTo(20);
}
@Test
public void givenListOfPosts_whenGroupedByAuthor_thenGetAMapUsingCollectingAndThen() {
Map<String, BlogPost.PostCountTitlesLikesStats> postsPerAuthor = posts.stream()
.collect(groupingBy(BlogPost::getAuthor, collectingAndThen(toList(), list -> {
long count = list.stream()
.map(BlogPost::getTitle)
.collect(counting());
String titles = list.stream()
.map(BlogPost::getTitle)
.collect(joining(" : "));
IntSummaryStatistics summary = list.stream()
.collect(summarizingInt(BlogPost::getLikes));
return new BlogPost.PostCountTitlesLikesStats(count, titles, summary);
})));
BlogPost.PostCountTitlesLikesStats result = postsPerAuthor.get("Author 1");
assertThat(result.postCount()).isEqualTo(3L);
assertThat(result.titles()).isEqualTo("News item 1 : Programming guide : Tech review 2");
assertThat(result.likesStats().getMax()).isEqualTo(20);
assertThat(result.likesStats().getMin()).isEqualTo(15);
assertThat(result.likesStats().getAverage()).isEqualTo(16.666d, offset(0.001d));
}
@Test
public void givenListOfPosts_whenGroupedByAuthor_thenGetAMapUsingToMap() {
int maxValLikes = 17;
Map<String, BlogPost.TitlesBoundedSumOfLikes> postsPerAuthor = posts.stream()
.collect(toMap(BlogPost::getAuthor, post -> {
int likes = (post.getLikes() > maxValLikes) ? maxValLikes : post.getLikes();
return new BlogPost.TitlesBoundedSumOfLikes(post.getTitle(), likes);
}, (u1, u2) -> {
int likes = (u2.boundedSumOfLikes() > maxValLikes) ? maxValLikes : u2.boundedSumOfLikes();
return new BlogPost.TitlesBoundedSumOfLikes(u1.titles()
.toUpperCase() + " : "
+ u2.titles()
.toUpperCase(),
u1.boundedSumOfLikes() + likes);
}));
BlogPost.TitlesBoundedSumOfLikes result = postsPerAuthor.get("Author 1");
assertThat(result.titles()).isEqualTo("NEWS ITEM 1 : PROGRAMMING GUIDE : TECH REVIEW 2");
assertThat(result.boundedSumOfLikes()).isEqualTo(47);
}
}
@@ -0,0 +1,80 @@
package com.baeldung.streams.map;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class StreamMapUnitTest {
private Map<String, String> books;
@Before
public void setup() {
books = new HashMap<>();
books.put("978-0201633610", "Design patterns : elements of reusable object-oriented software");
books.put("978-1617291999", "Java 8 in Action: Lambdas, Streams, and functional-style programming");
books.put("978-0134685991", "Effective Java");
}
@Test
public void whenOptionalVersionCalledForExistingTitle_thenReturnOptionalWithISBN() {
Optional<String> optionalIsbn = books.entrySet().stream()
.filter(e -> "Effective Java".equals(e.getValue()))
.map(Map.Entry::getKey).findFirst();
assertEquals("978-0134685991", optionalIsbn.get());
}
@Test
public void whenOptionalVersionCalledForNonExistingTitle_thenReturnEmptyOptionalForISBN() {
Optional<String> optionalIsbn = books.entrySet().stream()
.filter(e -> "Non Existent Title".equals(e.getValue()))
.map(Map.Entry::getKey).findFirst();
assertEquals(false, optionalIsbn.isPresent());
}
@Test
public void whenMultipleResultsVersionCalledForExistingTitle_aCollectionWithMultipleValuesIsReturned() {
books.put("978-0321356680", "Effective Java: Second Edition");
List<String> isbnCodes = books.entrySet().stream()
.filter(e -> e.getValue().startsWith("Effective Java"))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
assertTrue(isbnCodes.contains("978-0321356680"));
assertTrue(isbnCodes.contains("978-0134685991"));
}
@Test
public void whenMultipleResultsVersionCalledForNonExistingTitle_aCollectionWithNoValuesIsReturned() {
List<String> isbnCodes = books.entrySet().stream()
.filter(e -> e.getValue().startsWith("Spring"))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
assertTrue(isbnCodes.isEmpty());
}
@Test
public void whenKeysFollowingPatternReturnsAllValuesForThoseKeys() {
List<String> titlesForKeyPattern = books.entrySet().stream()
.filter(e -> e.getKey().startsWith("978-0"))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
assertEquals(2, titlesForKeyPattern.size());
assertTrue(titlesForKeyPattern.contains("Design patterns : elements of reusable object-oriented software"));
assertTrue(titlesForKeyPattern.contains("Effective Java"));
}
}
@@ -0,0 +1,46 @@
package com.baeldung.streams.parallel;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import static org.assertj.core.api.Assertions.assertThat;
class ForkJoinUnitTest {
@Test
void givenSequentialStreamOfNumbers_whenReducingSumWithIdentityFive_thenResultIsCorrect() {
List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
int sum = listOfNumbers.stream().reduce(5, Integer::sum);
assertThat(sum).isEqualTo(15);
}
@Test
void givenParallelStreamOfNumbers_whenReducingSumWithIdentityFive_thenResultIsNotCorrect() {
List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
int sum = listOfNumbers.parallelStream().reduce(5, Integer::sum);
assertThat(sum).isNotEqualTo(15);
}
@Test
void givenParallelStreamOfNumbers_whenReducingSumWithIdentityZero_thenResultIsCorrect() {
List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
int sum = listOfNumbers.parallelStream().reduce(0, Integer::sum) + 5;
assertThat(sum).isEqualTo(15);
}
@Test
public void givenParallelStreamOfNumbers_whenUsingCustomThreadPool_thenResultIsCorrect()
throws InterruptedException, ExecutionException {
List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
ForkJoinPool customThreadPool = new ForkJoinPool(4);
int sum = customThreadPool.submit(
() -> listOfNumbers.parallelStream().reduce(0, Integer::sum)).get();
customThreadPool.shutdown();
assertThat(sum).isEqualTo(10);
}
}
@@ -0,0 +1,81 @@
package com.baeldung.streams.reduce;
import static org.assertj.core.api.Assertions.assertThat;
import com.baeldung.streams.reduce.entities.User;
import com.baeldung.streams.reduce.utilities.NumberUtils;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
class StreamReduceUnitTest {
@Test
void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int result = numbers.stream().reduce(0, (subtotal, element) -> subtotal + element);
assertThat(result).isEqualTo(21);
}
@Test
void givenIntegerList_whenReduceWithSumAccumulatorMethodReference_thenCorrect() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int result = numbers.stream().reduce(0, Integer::sum);
assertThat(result).isEqualTo(21);
}
@Test
void givenStringList_whenReduceWithConcatenatorAccumulatorLambda_thenCorrect() {
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters.stream().reduce("", (partialString, element) -> partialString + element);
assertThat(result).isEqualTo("abcde");
}
@Test
void givenStringList_whenReduceWithConcatenatorAccumulatorMethodReference_thenCorrect() {
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters.stream().reduce("", String::concat);
assertThat(result).isEqualTo("abcde");
}
@Test
void givenStringList_whenReduceWithUppercaseConcatenatorAccumulator_thenCorrect() {
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase());
assertThat(result).isEqualTo("ABCDE");
}
@Test
void givenUserList_whenReduceWithAgeAccumulatorAndSumCombiner_thenCorrect() {
List<User> 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
void givenStringList_whenReduceWithParallelStream_thenCorrect() {
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters.parallelStream().reduce("", String::concat);
assertThat(result).isEqualTo("abcde");
}
@Test
void givenNumberUtilsClass_whenCalledDivideListElements_thenCorrect() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
assertThat(NumberUtils.divideListElements(numbers, 1)).isEqualTo(21);
}
@Test
void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlock_thenCorrect() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21);
}
@Test
void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
assertThat(NumberUtils.divideListElementsWithApplyFunctionMethod(numbers, 1)).isEqualTo(21);
}
}