diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index c1f674d39e..84dcfc60e9 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -6,15 +6,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index 0cd0cea4ac..1c11104ab2 100644
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -1,9 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 712ab9d985..b74a7f7384 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -6,6 +6,11 @@
+
+
+
+
+
diff --git a/.idea/jpa-buddy.xml b/.idea/jpa-buddy.xml
new file mode 100644
index 0000000000..d08f40080c
--- /dev/null
+++ b/.idea/jpa-buddy.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 17e19eb41d..d31b37ac7b 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,6 @@
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- 1619410137650
+
+ 1632408056518
- 1619410137650
-
+ 1632408056518
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- 1619410303516
+
+ 1632420206392
- 1619410303516
+ 1632420206392
-
+
+ 1632420268850
+
+
+
+ 1632420268850
+
+
+ 1632423632011
+
+
+
+ 1632423632011
+
+
+ 1632423824690
+
+
+
+ 1632423824690
+
+
+ 1632423847987
+
+
+
+ 1632423847987
+
+
+ 1632426542726
+
+
+
+ 1632426542726
+
+
+ 1632937568332
+
+
+
+ 1632937568332
+
+
+ 1632937611560
+
+
+
+ 1632937611560
+
+
+ 1633373116785
+
+
+
+ 1633373116785
+
+
+ 1633373171820
+
+
+
+ 1633373171820
+
+
+ 1633461594898
+
+
+
+ 1633461594898
+
+
+ 1633632799545
+
+
+
+ 1633632799545
+
+
+ 1636038085011
+
+
+
+ 1636038085011
+
+
+ 1637605886622
+
+
+
+ 1637605886622
+
+
+ 1637606120688
+
+
+
+ 1637606120688
+
+
+ 1637610032904
+
+
+
+ 1637610032904
+
+
+ 1646496865741
+
+
+
+ 1646496865741
+
+
+ 1646496916425
+
+
+
+ 1646496916425
+
+
+ 1649776367988
+
+
+
+ 1649776367988
+
+
+ 1650048905070
+
+
+
+ 1650048905070
+
+
+ 1650048942808
+
+
+
+ 1650048942808
+
+
@@ -78,7 +399,36 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jar://C:/Program Files/RedHat/java-11-openjdk-11.0.11-1/lib/src.zip!/java.base/java/lang/Integer.java
+ 1056
+
+
+
+
\ No newline at end of file
diff --git a/core-java-modules/core-java-8/.gitignore b/core-java-modules/core-java-8/.gitignore
new file mode 100644
index 0000000000..3de4cc647e
--- /dev/null
+++ b/core-java-modules/core-java-8/.gitignore
@@ -0,0 +1,26 @@
+*.class
+
+0.*
+
+#folders#
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+.resourceCache
+
+# Packaged files #
+*.jar
+*.war
+*.ear
+
+# Files generated by integration tests
+*.txt
+backup-pom.xml
+/bin/
+/temp
+
+#IntelliJ specific
+.idea/
+*.iml
\ No newline at end of file
diff --git a/core-java-modules/core-java-8/README.md b/core-java-modules/core-java-8/README.md
new file mode 100644
index 0000000000..72bdafe5fa
--- /dev/null
+++ b/core-java-modules/core-java-8/README.md
@@ -0,0 +1,15 @@
+## Core Java 8
+
+This module contains articles about Java 8 core features
+
+### Relevant Articles:
+- [New Features in Java 8](https://www.baeldung.com/java-8-new-features)
+- [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector)
+- [Strategy Design Pattern in Java 8](https://www.baeldung.com/java-strategy-pattern)
+- [Guide to Java 8 Comparator.comparing()](https://www.baeldung.com/java-8-comparator-comparing)
+- [Guide to the Java 8 forEach](https://www.baeldung.com/foreach-java)
+- [Introduction to Spliterator in Java](https://www.baeldung.com/java-spliterator)
+- [Finding Min/Max in an Array with Java](https://www.baeldung.com/java-array-min-max)
+- [Internationalization and Localization in Java 8](https://www.baeldung.com/java-8-localization)
+- [Generalized Target-Type Inference in Java](https://www.baeldung.com/java-generalized-target-type-inference)
+- [[More -->]](/core-java-modules/core-java-8-2)
diff --git a/core-java-modules/core-java-8/pom.xml b/core-java-modules/core-java-8/pom.xml
new file mode 100644
index 0000000000..c5ffa6e8ec
--- /dev/null
+++ b/core-java-modules/core-java-8/pom.xml
@@ -0,0 +1,55 @@
+
+
+ 4.0.0
+ core-java-8
+ 0.1.0-SNAPSHOT
+ core-java-8
+ jar
+
+
+ com.ossez.core-java-modules
+ core-java-modules
+ 0.0.2-SNAPSHOT
+
+
+
+
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+
+
+ core-java-8
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ 4.1
+
+ 3.6.1
+
+
+
\ No newline at end of file
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/aspect/ChangeCallsToCurrentTimeInMillisMethod.aj b/core-java-modules/core-java-8/src/main/java/com/ossez/aspect/ChangeCallsToCurrentTimeInMillisMethod.aj
new file mode 100644
index 0000000000..b28bebfdaf
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/aspect/ChangeCallsToCurrentTimeInMillisMethod.aj
@@ -0,0 +1,9 @@
+package com.baeldung.aspect;
+
+public aspect ChangeCallsToCurrentTimeInMillisMethod {
+ long around():
+ call(public static native long java.lang.System.currentTimeMillis())
+ && within(user.code.base.pckg.*) {
+ return 0;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/Address.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/Address.java
new file mode 100644
index 0000000000..8f6cd17e26
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/Address.java
@@ -0,0 +1,14 @@
+package com.ossez.java_8_features;
+
+public class Address {
+
+ private String street;
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/CustomException.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/CustomException.java
new file mode 100644
index 0000000000..5fb2a527de
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/CustomException.java
@@ -0,0 +1,4 @@
+package com.ossez.java_8_features;
+
+public class CustomException extends RuntimeException {
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/OptionalAddress.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/OptionalAddress.java
new file mode 100644
index 0000000000..7a17de1079
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/OptionalAddress.java
@@ -0,0 +1,16 @@
+package com.ossez.java_8_features;
+
+import java.util.Optional;
+
+public class OptionalAddress {
+
+ private String street;
+
+ public Optional getStreet() {
+ return Optional.ofNullable(street);
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/OptionalUser.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/OptionalUser.java
new file mode 100644
index 0000000000..ba519770ff
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/OptionalUser.java
@@ -0,0 +1,16 @@
+package com.ossez.java_8_features;
+
+import java.util.Optional;
+
+public class OptionalUser {
+
+ private OptionalAddress address;
+
+ public Optional getAddress() {
+ return Optional.of(address);
+ }
+
+ public void setAddress(OptionalAddress address) {
+ this.address = address;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/User.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/User.java
new file mode 100644
index 0000000000..c63cc2c956
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/User.java
@@ -0,0 +1,40 @@
+package com.ossez.java_8_features;
+
+import java.util.Optional;
+
+public class User {
+
+ private String name;
+
+ private Address address;
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+
+ public User() {
+ }
+
+ public User(String name) {
+ this.name = name;
+ }
+
+ public static boolean isRealUser(User user) {
+ return true;
+ }
+
+ public String getOrThrow() {
+ String value = null;
+ Optional valueOpt = Optional.ofNullable(value);
+ String result = valueOpt.orElseThrow(CustomException::new).toUpperCase();
+ return result;
+ }
+
+ public boolean isLegalName(String name) {
+ return name.length() > 3 && name.length() < 16;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/Vehicle.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/Vehicle.java
new file mode 100644
index 0000000000..110e8cc5e9
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/Vehicle.java
@@ -0,0 +1,18 @@
+package com.ossez.java_8_features;
+
+public interface Vehicle {
+
+ void moveTo(long altitude, long longitude);
+
+ static String producer() {
+ return "N&F Vehicles";
+ }
+
+ default long[] startPosition() {
+ return new long[] { 23, 15 };
+ }
+
+ default String getOverview() {
+ return "ATV made by " + producer();
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/VehicleImpl.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/VehicleImpl.java
new file mode 100644
index 0000000000..4bd702534d
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/VehicleImpl.java
@@ -0,0 +1,9 @@
+package com.ossez.java_8_features;
+
+public class VehicleImpl implements Vehicle {
+
+ @Override
+ public void moveTo(long altitude, long longitude) {
+ // do nothing
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/BlogPost.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/BlogPost.java
new file mode 100644
index 0000000000..44965f0ce2
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/BlogPost.java
@@ -0,0 +1,36 @@
+package com.ossez.java_8_features.groupingby;
+
+public class BlogPost {
+ private String title;
+ private String author;
+ private BlogPostType type;
+ private int likes;
+
+ 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 + '}';
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/BlogPostType.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/BlogPostType.java
new file mode 100644
index 0000000000..3b8eeb3da5
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/BlogPostType.java
@@ -0,0 +1,5 @@
+package com.ossez.java_8_features.groupingby;
+
+public enum BlogPostType {
+ NEWS, REVIEW, GUIDE
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/Tuple.java b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/Tuple.java
new file mode 100644
index 0000000000..1761e2757a
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/java_8_features/groupingby/Tuple.java
@@ -0,0 +1,41 @@
+package com.ossez.java_8_features.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 + '\'' + '}';
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingCommonsEmptyIfNull.java b/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingCommonsEmptyIfNull.java
new file mode 100644
index 0000000000..fb72c104ee
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingCommonsEmptyIfNull.java
@@ -0,0 +1,19 @@
+package com.ossez.nullsafecollectionstreams;
+
+import java.util.Collection;
+import java.util.stream.Stream;
+import static org.apache.commons.collections4.CollectionUtils.emptyIfNull;
+
+public class NullSafeCollectionStreamsUsingCommonsEmptyIfNull {
+
+ /**
+ * This method shows how to make a null safe stream from a collection through the use of
+ * emptyIfNull() method from Apache Commons CollectionUtils library
+ *
+ * @param collection The collection that is to be converted into a stream
+ * @return The stream that has been created from the collection or an empty stream if the collection is null
+ */
+ public Stream collectionAsStream(Collection collection) {
+ return emptyIfNull(collection).stream();
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingJava8OptionalContainer.java b/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingJava8OptionalContainer.java
new file mode 100644
index 0000000000..7ab449f232
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingJava8OptionalContainer.java
@@ -0,0 +1,21 @@
+package com.ossez.nullsafecollectionstreams;
+
+import java.util.Collection;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public class NullSafeCollectionStreamsUsingJava8OptionalContainer {
+
+ /**
+ * This method shows how to make a null safe stream from a collection through the use of
+ * Java SE 8’s Optional Container
+ *
+ * @param collection The collection that is to be converted into a stream
+ * @return The stream that has been created from the collection or an empty stream if the collection is null
+ */
+ public Stream collectionAsStream(Collection collection) {
+ return Optional.ofNullable(collection)
+ .map(Collection::stream)
+ .orElseGet(Stream::empty);
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingNullDereferenceCheck.java b/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingNullDereferenceCheck.java
new file mode 100644
index 0000000000..d06bd2e270
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingNullDereferenceCheck.java
@@ -0,0 +1,20 @@
+package com.ossez.nullsafecollectionstreams;
+
+import java.util.Collection;
+import java.util.stream.Stream;
+
+public class NullSafeCollectionStreamsUsingNullDereferenceCheck {
+
+ /**
+ * This method shows how to make a null safe stream from a collection through the use of a check
+ * to prevent null dereferences
+ *
+ * @param collection The collection that is to be converted into a stream
+ * @return The stream that has been created from the collection or an empty stream if the collection is null
+ */
+ public Stream collectionAsStream(Collection collection) {
+ return collection == null ? Stream.empty() : collection.stream();
+ }
+
+
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Article.java b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Article.java
new file mode 100644
index 0000000000..99784cbfbe
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Article.java
@@ -0,0 +1,44 @@
+package com.ossez.spliteratorAPI;
+
+import java.util.List;
+
+public class Article {
+ private List listOfAuthors;
+ private int id;
+ private String name;
+
+ public Article(String name) {
+ this.name = name;
+ }
+
+ public Article(List listOfAuthors, int id) {
+ super();
+ this.listOfAuthors = listOfAuthors;
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public List getListOfAuthors() {
+ return listOfAuthors;
+ }
+
+ public void setListOfAuthors(List listOfAuthors) {
+ this.listOfAuthors = listOfAuthors;
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Author.java b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Author.java
new file mode 100644
index 0000000000..68f9ae21f2
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Author.java
@@ -0,0 +1,33 @@
+package com.ossez.spliteratorAPI;
+
+public class Author {
+ private String name;
+ private int relatedArticleId;
+
+ public Author(String name, int relatedArticleId) {
+ this.name = name;
+ this.relatedArticleId = relatedArticleId;
+ }
+
+ public int getRelatedArticleId() {
+ return relatedArticleId;
+ }
+
+ public void setRelatedArticleId(int relatedArticleId) {
+ this.relatedArticleId = relatedArticleId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "[name: " + name + ", relatedId: " + relatedArticleId + "]";
+ }
+}
+
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Executor.java b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Executor.java
new file mode 100644
index 0000000000..894bd5ba66
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Executor.java
@@ -0,0 +1,19 @@
+package com.ossez.spliteratorAPI;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class Executor {
+
+ public static int countAutors(Stream stream) {
+ RelatedAuthorCounter wordCounter = stream.reduce(new RelatedAuthorCounter(0, true),
+ RelatedAuthorCounter::accumulate, RelatedAuthorCounter::combine);
+ return wordCounter.getCounter();
+ }
+
+ public static List generateElements() {
+ return Stream.generate(() -> new Article("Java")).limit(35000).collect(Collectors.toList());
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/RelatedAuthorCounter.java b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/RelatedAuthorCounter.java
new file mode 100644
index 0000000000..f6bca6ac3e
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/RelatedAuthorCounter.java
@@ -0,0 +1,27 @@
+package com.ossez.spliteratorAPI;
+
+public class RelatedAuthorCounter {
+ private final int counter;
+ private final boolean isRelated;
+
+ public RelatedAuthorCounter(int counter, boolean isRelated) {
+ this.counter = counter;
+ this.isRelated = isRelated;
+ }
+
+ public RelatedAuthorCounter accumulate(Author author) {
+ if (author.getRelatedArticleId() == 0) {
+ return isRelated ? this : new RelatedAuthorCounter(counter, true);
+ } else {
+ return isRelated ? new RelatedAuthorCounter(counter + 1, false) : this;
+ }
+ }
+
+ public RelatedAuthorCounter combine(RelatedAuthorCounter RelatedAuthorCounter) {
+ return new RelatedAuthorCounter(counter + RelatedAuthorCounter.counter, RelatedAuthorCounter.isRelated);
+ }
+
+ public int getCounter() {
+ return counter;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/RelatedAuthorSpliterator.java b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/RelatedAuthorSpliterator.java
new file mode 100644
index 0000000000..239747f7a5
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/RelatedAuthorSpliterator.java
@@ -0,0 +1,49 @@
+package com.ossez.spliteratorAPI;
+
+import java.util.List;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+public class RelatedAuthorSpliterator implements Spliterator {
+ private final List list;
+ AtomicInteger current = new AtomicInteger();
+
+ public RelatedAuthorSpliterator(List list) {
+ this.list = list;
+ }
+
+ @Override
+ public boolean tryAdvance(Consumer super Author> action) {
+
+ action.accept(list.get(current.getAndIncrement()));
+ return current.get() < list.size();
+ }
+
+ @Override
+ public Spliterator trySplit() {
+ int currentSize = list.size() - current.get();
+ if (currentSize < 10) {
+ return null;
+ }
+ for (int splitPos = currentSize / 2 + current.intValue(); splitPos < list.size(); splitPos++) {
+ if (list.get(splitPos).getRelatedArticleId() == 0) {
+ Spliterator spliterator = new RelatedAuthorSpliterator(list.subList(current.get(), splitPos));
+ current.set(splitPos);
+ return spliterator;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public long estimateSize() {
+ return list.size() - current.get();
+ }
+
+ @Override
+ public int characteristics() {
+ return CONCURRENT;
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Task.java b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Task.java
new file mode 100644
index 0000000000..e4bff0efa7
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/spliteratorAPI/Task.java
@@ -0,0 +1,27 @@
+package com.ossez.spliteratorAPI;
+
+import java.util.Spliterator;
+import java.util.concurrent.Callable;
+
+public class Task implements Callable {
+ private Spliterator spliterator;
+ private final static String SUFFIX = "- published by Baeldung";
+
+ public Task(Spliterator spliterator) {
+ this.spliterator = spliterator;
+ }
+
+ @Override
+ public String call() {
+ int current = 0;
+ while (spliterator.tryAdvance(article -> {
+ article.setName(article.getName()
+ .concat(SUFFIX));
+ })) {
+ current++;
+ }
+ ;
+ return Thread.currentThread()
+ .getName() + ":" + current;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/ChristmasDiscounter.java b/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/ChristmasDiscounter.java
new file mode 100644
index 0000000000..87532af1fd
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/ChristmasDiscounter.java
@@ -0,0 +1,11 @@
+package com.ossez.strategy;
+
+import java.math.BigDecimal;
+
+public class ChristmasDiscounter implements Discounter {
+
+ @Override
+ public BigDecimal apply(BigDecimal amount) {
+ return amount.multiply(BigDecimal.valueOf(0.9));
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/Discounter.java b/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/Discounter.java
new file mode 100644
index 0000000000..82e177638a
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/Discounter.java
@@ -0,0 +1,23 @@
+package com.ossez.strategy;
+
+import java.math.BigDecimal;
+import java.util.function.UnaryOperator;
+
+public interface Discounter extends UnaryOperator {
+
+ default Discounter combine(Discounter after) {
+ return value -> after.apply(this.apply(value));
+ }
+
+ static Discounter christmas() {
+ return (amount) -> amount.multiply(BigDecimal.valueOf(0.9));
+ }
+
+ static Discounter newYear() {
+ return (amount) -> amount.multiply(BigDecimal.valueOf(0.8));
+ }
+
+ static Discounter easter() {
+ return (amount) -> amount.multiply(BigDecimal.valueOf(0.5));
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/EasterDiscounter.java b/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/EasterDiscounter.java
new file mode 100644
index 0000000000..32d1c4d69e
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/strategy/EasterDiscounter.java
@@ -0,0 +1,11 @@
+package com.ossez.strategy;
+
+import java.math.BigDecimal;
+
+public class EasterDiscounter implements Discounter {
+
+ @Override
+ public BigDecimal apply(BigDecimal amount) {
+ return amount.multiply(BigDecimal.valueOf(0.5));
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/application/Application.java b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/application/Application.java
new file mode 100644
index 0000000000..07a58b70b6
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/application/Application.java
@@ -0,0 +1,63 @@
+package com.ossez.streamreduce.application;
+
+import com.ossez.streamreduce.entities.User;
+import com.ossez.streamreduce.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, (a, b) -> a + b);
+ 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("", (a, b) -> a + b);
+ System.out.println(result3);
+
+ String result4 = letters.stream().reduce("", String::concat);
+ System.out.println(result4);
+
+ String result5 = letters.stream().reduce("", (a, b) -> a.toUpperCase() + b.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);
+
+ List userList = new ArrayList<>();
+ for (int i = 0; i <= 1000000; i++) {
+ userList.add(new User("John" + i, i));
+ }
+
+ long t1 = System.currentTimeMillis();
+ int result9 = userList.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ long t2 = System.currentTimeMillis();
+ System.out.println(result9);
+ System.out.println("Sequential stream time: " + (t2 - t1) + "ms");
+
+ long t3 = System.currentTimeMillis();
+ int result10 = userList.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ long t4 = System.currentTimeMillis();
+ System.out.println(result10);
+ System.out.println("Parallel stream time: " + (t4 - t3) + "ms");
+
+ int result11 = NumberUtils.divideListElements(numbers, 1);
+ System.out.println(result11);
+
+ int result12 = NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 0);
+ System.out.println(result12);
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/Rating.java b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/Rating.java
new file mode 100644
index 0000000000..a36371dde1
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/Rating.java
@@ -0,0 +1,39 @@
+package com.ossez.streamreduce.entities;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Rating {
+
+ double points;
+ List 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 getReviews() {
+ return reviews;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/Review.java b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/Review.java
new file mode 100644
index 0000000000..3f63d00f98
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/Review.java
@@ -0,0 +1,28 @@
+package com.ossez.streamreduce.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;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/User.java b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/User.java
new file mode 100644
index 0000000000..949b9ef388
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/entities/User.java
@@ -0,0 +1,30 @@
+package com.ossez.streamreduce.entities;
+
+public class User {
+
+ private final String name;
+ private final int age;
+ private final Rating rating = new Rating();
+
+ public User(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public Rating getRating() {
+ return rating;
+ }
+
+ @Override
+ public String toString() {
+ return "User{" + "name=" + name + ", age=" + age + '}';
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/utilities/NumberUtils.java b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/utilities/NumberUtils.java
new file mode 100644
index 0000000000..b36c4b3554
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/java/com/ossez/streamreduce/utilities/NumberUtils.java
@@ -0,0 +1,52 @@
+package com.ossez.streamreduce.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 occurred!");
+ }
+ return 0;
+ }
+}
diff --git a/core-java-modules/core-java-8/src/main/resources/logback.xml b/core-java-modules/core-java-8/src/main/resources/logback.xml
new file mode 100644
index 0000000000..11032b47f4
--- /dev/null
+++ b/core-java-modules/core-java-8/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/internationalization/DateFormatUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/internationalization/DateFormatUnitTest.java
new file mode 100644
index 0000000000..2e7a140f5a
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/internationalization/DateFormatUnitTest.java
@@ -0,0 +1,110 @@
+package com.ossez.internationalization;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class DateFormatUnitTest {
+
+ @Test
+ public void givenGregorianCalendar_whenLocaleSpecificDateInstance_givenLanguageSpecificMonths() {
+ GregorianCalendar gregorianCalendar = new GregorianCalendar(2018, 1, 1, 10, 15, 20);
+ Date date = gregorianCalendar.getTime();
+
+ DateFormat itInstance = DateFormat.getDateInstance(DateFormat.FULL, Locale.ITALY);
+ DateFormat usInstance = DateFormat.getDateInstance(DateFormat.FULL, Locale.US);
+
+ Assert.assertEquals("giovedì 1 febbraio 2018", itInstance.format(date));
+ Assert.assertEquals("Thursday, February 1, 2018", usInstance.format(date));
+ }
+
+ @Test
+ public void givenGregorianCalendar_whenDateInstanceWithDifferentFormats_givenSpecificDateFormatting() {
+ GregorianCalendar gregorianCalendar = new GregorianCalendar(2018, 1, 1, 10, 15, 20);
+ Date date = gregorianCalendar.getTime();
+
+ DateFormat fullInstance = DateFormat.getDateInstance(DateFormat.FULL, Locale.ITALY);
+ DateFormat mediumInstance = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.ITALY);
+
+ Assert.assertEquals("giovedì 1 febbraio 2018", fullInstance.format(date));
+ Assert.assertEquals("1-feb-2018", mediumInstance.format(date));
+ }
+
+ @Test
+ public void givenGregorianCalendar_whenTimeInstanceWithDifferentFormats_givenSpecificTimeFormatting() {
+ GregorianCalendar gregorianCalendar = new GregorianCalendar(2018, 1, 1, 10, 15, 20);
+ gregorianCalendar.setTimeZone(TimeZone.getTimeZone("CET"));
+ TimeZone.setDefault(TimeZone.getTimeZone("CET"));
+ Date date = gregorianCalendar.getTime();
+
+ DateFormat fullInstance = DateFormat.getTimeInstance(DateFormat.FULL, Locale.ITALY);
+ DateFormat mediumInstance = DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.ITALY);
+
+ Assert.assertEquals("10.15.20 CET", fullInstance.format(date));
+ Assert.assertEquals("10.15.20" , mediumInstance.format(date));
+ }
+
+ @Test
+ public void givenGregorianCalendar_whenDateTimeInstanceWithDifferentFormats_givenSpecificDateTimeFormatting() {
+ GregorianCalendar gregorianCalendar = new GregorianCalendar(2018, 1, 1, 10, 15, 20);
+ gregorianCalendar.setTimeZone(TimeZone.getTimeZone("CET"));
+ TimeZone.setDefault(TimeZone.getTimeZone("CET"));
+ Date date = gregorianCalendar.getTime();
+
+ DateFormat ffInstance = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.ITALY);
+ DateFormat smInstance = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.ITALY);
+
+ Assert.assertEquals("giovedì 1 febbraio 2018 10.15.20 CET", ffInstance.format(date));
+ Assert.assertEquals("01/02/18 10.15.20", smInstance.format(date));
+ }
+
+ @Test
+ public void givenGregorianCalendar_whenLocaleSpecificDateTimeInstance_givenLocaleSpecificFormatting() {
+ GregorianCalendar gregorianCalendar = new GregorianCalendar(2018, 1, 1, 10, 15, 20);
+ gregorianCalendar.setTimeZone(TimeZone.getTimeZone("CET"));
+ TimeZone.setDefault(TimeZone.getTimeZone("CET"));
+ Date date = gregorianCalendar.getTime();
+
+ DateFormat itInstance = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.ITALY);
+ DateFormat jpInstance = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.JAPAN);
+
+ Assert.assertEquals("giovedì 1 febbraio 2018 10.15.20 CET", itInstance.format(date));
+ Assert.assertEquals("2018年2月1日 10時15分20秒 CET", jpInstance.format(date));
+ }
+
+ @Test
+ public void givenGregorianCalendar_whenCustomizedSimpleDateFormat_thenSpecificMonthRepresentations() {
+ GregorianCalendar gregorianCalendar = new GregorianCalendar(2018, 1, 1, 10, 15, 20);
+ Date date = gregorianCalendar.getTime();
+ Locale.setDefault(new Locale("pl", "PL"));
+
+ SimpleDateFormat fullMonthDateFormat = new SimpleDateFormat("dd-MMMM-yyyy HH:mm:ss:SSS");
+ SimpleDateFormat shortMonthsimpleDateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss:SSS");
+
+ Assert.assertEquals("01-lutego-2018 10:15:20:000", fullMonthDateFormat.format(date));
+ Assert.assertEquals("01-02-2018 10:15:20:000" , shortMonthsimpleDateFormat.format(date));
+ }
+
+ @Test
+ public void givenGregorianCalendar_whenCustomizedDateFormatSymbols_thenChangedDayNames() {
+ GregorianCalendar gregorianCalendar = new GregorianCalendar(2018, 1, 1, 10, 15, 20);
+ Date date = gregorianCalendar.getTime();
+ Locale.setDefault(new Locale("pl", "PL"));
+
+ DateFormatSymbols dateFormatSymbols = new DateFormatSymbols();
+ dateFormatSymbols.setWeekdays(new String[]{"A", "B", "C", "D", "E", "F", "G", "H"});
+ SimpleDateFormat standardDateFormat = new SimpleDateFormat("EEEE-MMMM-yyyy HH:mm:ss:SSS");
+ SimpleDateFormat newDaysDateFormat = new SimpleDateFormat("EEEE-MMMM-yyyy HH:mm:ss:SSS", dateFormatSymbols);
+
+ Assert.assertEquals("czwartek-lutego-2018 10:15:20:000", standardDateFormat.format(date));
+ Assert.assertEquals("F-lutego-2018 10:15:20:000", newDaysDateFormat.format(date));
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/internationalization/NumbersCurrenciesFormattingUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/internationalization/NumbersCurrenciesFormattingUnitTest.java
new file mode 100644
index 0000000000..db59219d7f
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/internationalization/NumbersCurrenciesFormattingUnitTest.java
@@ -0,0 +1,76 @@
+package com.ossez.internationalization;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.Currency;
+import java.util.Locale;
+
+public class NumbersCurrenciesFormattingUnitTest {
+
+ @Test
+ public void givenDifferentLocalesAndDoubleNumber_whenNumberInstance_thenDifferentOutput() {
+ Locale usLocale = Locale.US;
+ Locale plLocale = new Locale("pl", "PL");
+ Locale deLocale = Locale.GERMANY;
+ double number = 102_300.456d;
+
+ NumberFormat usNumberFormat = NumberFormat.getInstance(usLocale);
+ NumberFormat plNumberFormat = NumberFormat.getInstance(plLocale);
+ NumberFormat deNumberFormat = NumberFormat.getInstance(deLocale);
+
+ Assert.assertEquals(usNumberFormat.format(number), "102,300.456");
+ Assert.assertEquals(plNumberFormat.format(number), "102 300,456");
+ Assert.assertEquals(deNumberFormat.format(number), "102.300,456");
+ }
+
+ @Test
+ public void givenDifferentLocalesAndDoubleAmount_whenCurrencyInstance_thenDifferentOutput() {
+ Locale usLocale = Locale.US;
+ Locale plLocale = new Locale("pl", "PL");
+ Locale deLocale = Locale.GERMANY;
+ BigDecimal number = new BigDecimal(102_300.456d);
+
+ NumberFormat usNumberFormat = NumberFormat.getCurrencyInstance(usLocale);
+ NumberFormat plNumberFormat = NumberFormat.getCurrencyInstance(plLocale);
+ NumberFormat deNumberFormat = NumberFormat.getCurrencyInstance(deLocale);
+
+ Assert.assertEquals(usNumberFormat.format(number), "$102,300.46");
+ Assert.assertEquals(plNumberFormat.format(number), "102 300,46 zł");
+ Assert.assertEquals(deNumberFormat.format(number), "102.300,46 €");
+ }
+
+ @Test
+ public void givenLocaleAndNumber_whenSpecificDecimalFormat_thenSpecificOutput() {
+ Locale.setDefault(Locale.FRANCE);
+ BigDecimal number = new BigDecimal(102_300.456d);
+
+ DecimalFormat zeroDecimalFormat = new DecimalFormat("000000000.0000");
+ DecimalFormat hashDecimalFormat = new DecimalFormat("###,###.#");
+ DecimalFormat dollarDecimalFormat = new DecimalFormat("$###,###.##");
+
+ Assert.assertEquals(zeroDecimalFormat.format(number), "000102300,4560");
+ Assert.assertEquals(hashDecimalFormat.format(number), "102 300,5");
+ Assert.assertEquals(dollarDecimalFormat.format(number), "$102 300,46");
+ }
+
+ @Test
+ public void givenLocaleAndNumber_whenSpecificDecimalFormatSymbols_thenSpecificOutput() {
+ Locale.setDefault(Locale.FRANCE);
+ BigDecimal number = new BigDecimal(102_300.456d);
+
+ DecimalFormatSymbols decimalFormatSymbols = DecimalFormatSymbols.getInstance();
+ decimalFormatSymbols.setGroupingSeparator('^');
+ decimalFormatSymbols.setDecimalSeparator('@');
+ DecimalFormat separatorsDecimalFormat = new DecimalFormat("$###,###.##");
+ separatorsDecimalFormat.setGroupingSize(4);
+ separatorsDecimalFormat.setCurrency(Currency.getInstance(Locale.JAPAN));
+ separatorsDecimalFormat.setDecimalFormatSymbols(decimalFormatSymbols);
+
+ Assert.assertEquals(separatorsDecimalFormat.format(number), "$10^2300@46");
+ }
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8DefaultStaticIntefaceMethodsUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8DefaultStaticIntefaceMethodsUnitTest.java
new file mode 100644
index 0000000000..8a1b0705f5
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8DefaultStaticIntefaceMethodsUnitTest.java
@@ -0,0 +1,27 @@
+package com.ossez.java8;
+
+import com.ossez.java_8_features.Vehicle;
+import com.ossez.java_8_features.VehicleImpl;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class Java8DefaultStaticIntefaceMethodsUnitTest {
+
+ @Test
+ public void callStaticInterfaceMethdosMethods_whenExpectedResults_thenCorrect() {
+ Vehicle vehicle = new VehicleImpl();
+ String overview = vehicle.getOverview();
+ long[] startPosition = vehicle.startPosition();
+
+ assertEquals(overview, "ATV made by N&F Vehicles");
+ assertEquals(startPosition[0], 23);
+ assertEquals(startPosition[1], 15);
+ }
+
+ @Test
+ public void callDefaultInterfaceMethods_whenExpectedResults_thenCorrect() {
+ String producer = Vehicle.producer();
+ assertEquals(producer, "N&F Vehicles");
+ }
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8ForEachUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8ForEachUnitTest.java
new file mode 100644
index 0000000000..8c1a2fba03
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8ForEachUnitTest.java
@@ -0,0 +1,133 @@
+package com.ossez.java8;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+
+import com.google.common.collect.Lists;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Java8ForEachUnitTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(Java8ForEachUnitTest.class);
+
+ @Test
+ public void compareForEachMethods_thenPrintResults() {
+
+ List names = new ArrayList<>();
+ names.add("Larry");
+ names.add("Steve");
+ names.add("James");
+ names.add("Conan");
+ names.add("Ellen");
+
+ // Java 5 - for-loop
+ logger.debug("--- Enhanced for-loop ---");
+ for (String name : names) {
+ logger.debug(name);
+ }
+
+ // Java 8 - forEach
+ names.forEach(name -> {
+ System.out.println(name);
+ });
+
+ logger.debug("--- Print Consumer ---");
+ Consumer printConsumer = new Consumer() {
+ public void accept(String name) {
+ System.out.println(name);
+ }
+
+ ;
+ };
+
+ names.forEach(printConsumer);
+
+ // Anonymous inner class that implements Consumer interface
+ logger.debug("--- Anonymous inner class ---");
+ names.forEach(new Consumer() {
+ public void accept(String name) {
+ logger.debug(name);
+ }
+ });
+
+ // Java 8 - forEach - Lambda Syntax
+ logger.debug("--- forEach method ---");
+ names.forEach(name -> logger.debug(name));
+
+ // Java 8 - forEach - Print elements using a Method Reference
+ logger.debug("--- Method Reference ---");
+ names.forEach(logger::debug);
+ }
+
+ @Test
+ public void givenList_thenIterateAndPrintResults() {
+ List names = Arrays.asList("Larry", "Steve", "James");
+
+ names.forEach(System.out::println);
+ }
+
+ @Test
+ public void givenSet_thenIterateAndPrintResults() {
+ Set uniqueNames = new HashSet<>(Arrays.asList("Larry", "Steve", "James"));
+
+ uniqueNames.forEach(System.out::println);
+ }
+
+ @Test
+ public void givenQueue_thenIterateAndPrintResults() {
+ Queue namesQueue = new ArrayDeque<>(Arrays.asList("Larry", "Steve", "James"));
+
+ namesQueue.forEach(System.out::println);
+ }
+
+ @Test
+ public void givenMap_thenIterateAndPrintResults() {
+ Map namesMap = new HashMap<>();
+ namesMap.put(1, "Larry");
+ namesMap.put(2, "Steve");
+ namesMap.put(3, "James");
+
+ namesMap.entrySet()
+ .forEach(entry -> System.out.println(entry.getKey() + " " + entry.getValue()));
+ }
+
+ @Test
+ public void givenMap_whenUsingBiConsumer_thenIterateAndPrintResults2() {
+ Map namesMap = new HashMap<>();
+ namesMap.put(1, "Larry");
+ namesMap.put(2, "Steve");
+ namesMap.put(3, "James");
+
+ namesMap.forEach((key, value) -> System.out.println(key + " " + value));
+ }
+
+ @Test
+ public void testIteratorAndFor() {
+ List testList = Arrays.asList("A", "B", "C");
+
+ Iterator iterator = testList.iterator();
+ while (iterator.hasNext()) {
+ logger.debug((String) iterator.next());
+
+ }
+
+ logger.debug("--- FOR ---");
+ for (int i = 0; i < testList.size(); i++) {
+ logger.debug("{} > {}", i, testList.get(i));
+ }
+
+ logger.debug("--- FOR LOOP ---");
+ for (String s : testList) {
+ logger.debug(s);
+ }
+
+ logger.debug("--- FOR EACH ---");
+ testList.forEach(s -> {
+ logger.debug(s);
+ });
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8MethodReferenceUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8MethodReferenceUnitTest.java
new file mode 100644
index 0000000000..3f3fe24bbc
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8MethodReferenceUnitTest.java
@@ -0,0 +1,67 @@
+package com.ossez.java8;
+
+import com.ossez.java_8_features.User;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class Java8MethodReferenceUnitTest {
+
+ private List 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 checkStaticMethodReferences_whenWork_thenCorrect() {
+
+ List users = new ArrayList<>();
+ users.add(new User());
+ users.add(new User());
+ boolean isReal = users.stream().anyMatch(u -> User.isRealUser(u));
+ boolean isRealRef = users.stream().anyMatch(User::isRealUser);
+ assertTrue(isReal);
+ assertTrue(isRealRef);
+ }
+
+ @Test
+ public void checkInstanceMethodReferences_whenWork_thenCorrect() {
+ User user = new User();
+ boolean isLegalName = list.stream().anyMatch(user::isLegalName);
+ assertTrue(isLegalName);
+ }
+
+ @Test
+ public void checkParticularTypeReferences_whenWork_thenCorrect() {
+ long count = list.stream().filter(String::isEmpty).count();
+ assertEquals(count, 2);
+ }
+
+ @Test
+ public void checkConstructorReferences_whenWork_thenCorrect() {
+ Stream stream = list.stream().map(User::new);
+ List userList = stream.collect(Collectors.toList());
+ assertEquals(userList.size(), list.size());
+ assertTrue(userList.get(0) instanceof User);
+ }
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8OptionalUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8OptionalUnitTest.java
new file mode 100644
index 0000000000..9f408cf577
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/Java8OptionalUnitTest.java
@@ -0,0 +1,116 @@
+package com.ossez.java8;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.ossez.java_8_features.Address;
+import com.ossez.java_8_features.CustomException;
+import com.ossez.java_8_features.OptionalAddress;
+import com.ossez.java_8_features.OptionalUser;
+import com.ossez.java_8_features.User;
+
+public class Java8OptionalUnitTest {
+
+ private List 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 checkOptional_whenAsExpected_thenCorrect() {
+ Optional optionalEmpty = Optional.empty();
+ assertFalse(optionalEmpty.isPresent());
+
+ String str = "value";
+ Optional optional = Optional.of(str);
+ assertEquals(optional.get(), "value");
+
+ Optional optionalNullable = Optional.ofNullable(str);
+ Optional optionalNull = Optional.ofNullable(null);
+ assertEquals(optionalNullable.get(), "value");
+ assertFalse(optionalNull.isPresent());
+
+ List listOpt = Optional.of(list).orElse(new ArrayList<>());
+ List listNull = null;
+ List listOptNull = Optional.ofNullable(listNull).orElse(new ArrayList<>());
+ assertTrue(listOpt == list);
+ assertTrue(listOptNull.isEmpty());
+
+ Optional user = Optional.ofNullable(getUser());
+ String result = user.map(User::getAddress).map(Address::getStreet).orElse("not specified");
+ assertEquals(result, "1st Avenue");
+
+ Optional optionalUser = Optional.ofNullable(getOptionalUser());
+ String resultOpt = optionalUser.flatMap(OptionalUser::getAddress).flatMap(OptionalAddress::getStreet).orElse("not specified");
+ assertEquals(resultOpt, "1st Avenue");
+
+ Optional userNull = Optional.ofNullable(getUserNull());
+ String resultNull = userNull.map(User::getAddress).map(Address::getStreet).orElse("not specified");
+ assertEquals(resultNull, "not specified");
+
+ Optional optionalUserNull = Optional.ofNullable(getOptionalUserNull());
+ String resultOptNull = optionalUserNull.flatMap(OptionalUser::getAddress).flatMap(OptionalAddress::getStreet).orElse("not specified");
+ assertEquals(resultOptNull, "not specified");
+
+ }
+
+ @Test(expected = CustomException.class)
+ public void callMethod_whenCustomException_thenCorrect() {
+ User user = new User();
+ String result = user.getOrThrow();
+ }
+
+ private User getUser() {
+ User user = new User();
+ Address address = new Address();
+ address.setStreet("1st Avenue");
+ user.setAddress(address);
+ return user;
+ }
+
+ private OptionalUser getOptionalUser() {
+ OptionalUser user = new OptionalUser();
+ OptionalAddress address = new OptionalAddress();
+ address.setStreet("1st Avenue");
+ user.setAddress(address);
+ return user;
+ }
+
+ private OptionalUser getOptionalUserNull() {
+ OptionalUser user = new OptionalUser();
+ OptionalAddress address = new OptionalAddress();
+ address.setStreet(null);
+ user.setAddress(address);
+ return user;
+ }
+
+ private User getUserNull() {
+ User user = new User();
+ Address address = new Address();
+ address.setStreet(null);
+ user.setAddress(address);
+ return user;
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/java8/comparator/Employee.java b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/comparator/Employee.java
new file mode 100644
index 0000000000..7030f4c2a1
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/comparator/Employee.java
@@ -0,0 +1,22 @@
+package com.ossez.java8.comparator;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@AllArgsConstructor
+@ToString
+@EqualsAndHashCode
+public class Employee implements Comparable{
+ String name;
+ int age;
+ double salary;
+ long mobile;
+
+ @Override
+ public int compareTo(Employee argEmployee) {
+ return name.compareTo(argEmployee.getName());
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/java8/comparator/Java8ComparatorUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/comparator/Java8ComparatorUnitTest.java
new file mode 100644
index 0000000000..252967fb04
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/java8/comparator/Java8ComparatorUnitTest.java
@@ -0,0 +1,152 @@
+package com.ossez.java8.comparator;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class Java8ComparatorUnitTest {
+
+ private Employee[] employees;
+ private Employee[] employeesArrayWithNulls;
+ private Employee[] sortedEmployeesByName;
+ private Employee[] sortedEmployeesByNameDesc;
+ private Employee[] sortedEmployeesByAge;
+ private Employee[] sortedEmployeesByMobile;
+ private Employee[] sortedEmployeesBySalary;
+ private Employee[] sortedEmployeesArray_WithNullsFirst;
+ private Employee[] sortedEmployeesArray_WithNullsLast;
+ private Employee[] sortedEmployeesByNameAge;
+ private Employee[] someMoreEmployees;
+ private Employee[] sortedEmployeesByAgeName;;
+
+ @Before
+ public void initData() {
+ employees = new Employee[] { new Employee("John", 25, 3000, 9922001), new Employee("Ace", 22, 2000, 5924001), new Employee("Keith", 35, 4000, 3924401) };
+ employeesArrayWithNulls = new Employee[] { new Employee("John", 25, 3000, 9922001), null, new Employee("Ace", 22, 2000, 5924001), null, new Employee("Keith", 35, 4000, 3924401) };
+
+ sortedEmployeesByName = new Employee[] { new Employee("Ace", 22, 2000, 5924001), new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) };
+ sortedEmployeesByNameDesc = new Employee[] { new Employee("Keith", 35, 4000, 3924401), new Employee("John", 25, 3000, 9922001), new Employee("Ace", 22, 2000, 5924001) };
+
+ sortedEmployeesByAge = new Employee[] { new Employee("Ace", 22, 2000, 5924001), new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) };
+
+ sortedEmployeesByMobile = new Employee[] { new Employee("Keith", 35, 4000, 3924401), new Employee("Ace", 22, 2000, 5924001), new Employee("John", 25, 3000, 9922001), };
+
+ sortedEmployeesBySalary = new Employee[] { new Employee("Ace", 22, 2000, 5924001), new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401), };
+
+ sortedEmployeesArray_WithNullsFirst = new Employee[] { null, null, new Employee("Ace", 22, 2000, 5924001), new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) };
+ sortedEmployeesArray_WithNullsLast = new Employee[] { new Employee("Ace", 22, 2000, 5924001), new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401), null, null };
+
+ someMoreEmployees = new Employee[] { new Employee("Jake", 25, 3000, 9922001), new Employee("Jake", 22, 2000, 5924001), new Employee("Ace", 22, 3000, 6423001), new Employee("Keith", 35, 4000, 3924401) };
+
+ sortedEmployeesByAgeName = new Employee[] { new Employee("Ace", 22, 3000, 6423001), new Employee("Jake", 22, 2000, 5924001), new Employee("Jake", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) };
+ sortedEmployeesByNameAge = new Employee[] { new Employee("Ace", 22, 3000, 6423001), new Employee("Jake", 22, 2000, 5924001), new Employee("Jake", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) };
+ }
+
+ @Test
+ public void whenComparing_thenSortedByName() {
+ Comparator employeeNameComparator = Comparator.comparing(Employee::getName);
+ Arrays.sort(employees, employeeNameComparator);
+ // System.out.println(Arrays.toString(employees));
+ assertTrue(Arrays.equals(employees, sortedEmployeesByName));
+ }
+
+ @Test
+ public void whenComparingWithComparator_thenSortedByNameDesc() {
+ Comparator employeeNameComparator = Comparator.comparing(Employee::getName, (s1, s2) -> {
+ return s2.compareTo(s1);
+ });
+ Arrays.sort(employees, employeeNameComparator);
+ // System.out.println(Arrays.toString(employees));
+ assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc));
+ }
+
+ @Test
+ public void whenReversed_thenSortedByNameDesc() {
+ Comparator employeeNameComparator = Comparator.comparing(Employee::getName);
+ Comparator employeeNameComparatorReversed = employeeNameComparator.reversed();
+ Arrays.sort(employees, employeeNameComparatorReversed);
+ // System.out.println(Arrays.toString(employees));
+ assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc));
+ }
+
+ @Test
+ public void whenComparingInt_thenSortedByAge() {
+ Comparator employeeAgeComparator = Comparator.comparingInt(Employee::getAge);
+ Arrays.sort(employees, employeeAgeComparator);
+ // System.out.println(Arrays.toString(employees));
+ assertTrue(Arrays.equals(employees, sortedEmployeesByAge));
+ }
+
+ @Test
+ public void whenComparingLong_thenSortedByMobile() {
+ Comparator employeeMobileComparator = Comparator.comparingLong(Employee::getMobile);
+ Arrays.sort(employees, employeeMobileComparator);
+ // System.out.println(Arrays.toString(employees));
+ assertTrue(Arrays.equals(employees, sortedEmployeesByMobile));
+ }
+
+ @Test
+ public void whenComparingDouble_thenSortedBySalary() {
+ Comparator employeeSalaryComparator = Comparator.comparingDouble(Employee::getSalary);
+ Arrays.sort(employees, employeeSalaryComparator);
+ // System.out.println(Arrays.toString(employees));
+ assertTrue(Arrays.equals(employees, sortedEmployeesBySalary));
+ }
+
+ @Test
+ public void whenNaturalOrder_thenSortedByName() {
+ Comparator employeeNameComparator = Comparator. naturalOrder();
+ Arrays.sort(employees, employeeNameComparator);
+ // System.out.println(Arrays.toString(employees));
+ assertTrue(Arrays.equals(employees, sortedEmployeesByName));
+ }
+
+ @Test
+ public void whenReverseOrder_thenSortedByNameDesc() {
+ Comparator employeeNameComparator = Comparator. reverseOrder();
+ Arrays.sort(employees, employeeNameComparator);
+ // System.out.println(Arrays.toString(employees));
+ assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc));
+ }
+
+ @Test
+ public void whenNullsFirst_thenSortedByNameWithNullsFirst() {
+ Comparator employeeNameComparator = Comparator.comparing(Employee::getName);
+ Comparator employeeNameComparator_nullFirst = Comparator.nullsFirst(employeeNameComparator);
+ Arrays.sort(employeesArrayWithNulls, employeeNameComparator_nullFirst);
+ // System.out.println(Arrays.toString(employeesArrayWithNulls));
+ assertTrue(Arrays.equals(employeesArrayWithNulls, sortedEmployeesArray_WithNullsFirst));
+ }
+
+ @Test
+ public void whenNullsLast_thenSortedByNameWithNullsLast() {
+ Comparator employeeNameComparator = Comparator.comparing(Employee::getName);
+ Comparator employeeNameComparator_nullLast = Comparator.nullsLast(employeeNameComparator);
+ Arrays.sort(employeesArrayWithNulls, employeeNameComparator_nullLast);
+ // System.out.println(Arrays.toString(employeesArrayWithNulls));
+ assertTrue(Arrays.equals(employeesArrayWithNulls, sortedEmployeesArray_WithNullsLast));
+ }
+
+ @Test
+ public void whenThenComparing_thenSortedByAgeName() {
+ Comparator employee_Age_Name_Comparator = Comparator.comparing(Employee::getAge).thenComparing(Employee::getName);
+
+ Arrays.sort(someMoreEmployees, employee_Age_Name_Comparator);
+ // System.out.println(Arrays.toString(someMoreEmployees));
+ assertTrue(Arrays.equals(someMoreEmployees, sortedEmployeesByAgeName));
+ }
+
+ @Test
+ public void whenThenComparing_thenSortedByNameAge() {
+ Comparator employee_Name_Age_Comparator = Comparator.comparing(Employee::getName).thenComparingInt(Employee::getAge);
+
+ Arrays.sort(someMoreEmployees, employee_Name_Age_Comparator);
+ // System.out.println(Arrays.toString(someMoreEmployees));
+ assertTrue(Arrays.equals(someMoreEmployees, sortedEmployeesByNameAge));
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/java_8_features/groupingby/Java8GroupingByCollectorUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/java_8_features/groupingby/Java8GroupingByCollectorUnitTest.java
new file mode 100644
index 0000000000..b4185e9156
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/java_8_features/groupingby/Java8GroupingByCollectorUnitTest.java
@@ -0,0 +1,215 @@
+package com.ossez.java_8_features.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.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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.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.junit.Test;
+
+public class Java8GroupingByCollectorUnitTest {
+
+ private static final List 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
+ public void givenAListOfPosts_whenGroupedByType_thenGetAMapBetweenTypeAndPosts() {
+ Map> 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
+ public void givenAListOfPosts_whenGroupedByTypeAndTheirTitlesAreJoinedInAString_thenGetAMapBetweenTypeAndCsvTitles() {
+ Map 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
+ public void givenAListOfPosts_whenGroupedByTypeAndSumTheLikes_thenGetAMapBetweenTypeAndPostLikes() {
+ Map 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
+ public void givenAListOfPosts_whenGroupedByTypeInAnEnumMap_thenGetAnEnumMapBetweenTypeAndPosts() {
+ EnumMap> 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
+ public void givenAListOfPosts_whenGroupedByTypeInSets_thenGetAMapBetweenTypesAndSetsOfPosts() {
+ Map> 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
+ public void givenAListOfPosts_whenGroupedByTypeConcurrently_thenGetAMapBetweenTypeAndPosts() {
+ ConcurrentMap> 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
+ public void givenAListOfPosts_whenGroupedByTypeAndAveragingLikes_thenGetAMapBetweenTypeAndAverageNumberOfLikes() {
+ Map 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
+ public void givenAListOfPosts_whenGroupedByTypeAndCounted_thenGetAMapBetweenTypeAndNumberOfPosts() {
+ Map 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
+ public void givenAListOfPosts_whenGroupedByTypeAndMaxingLikes_thenGetAMapBetweenTypeAndMaximumNumberOfLikes() {
+ Map> 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
+ public void givenAListOfPosts_whenGroupedByAuthorAndThenByType_thenGetAMapBetweenAuthorAndMapsBetweenTypeAndBlogPosts() {
+ Map>> 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
+ public void givenAListOfPosts_whenGroupedByTypeAndSummarizingLikes_thenGetAMapBetweenTypeAndSummary() {
+ Map 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
+ public void givenAListOfPosts_whenGroupedByComplexMapKeyType_thenGetAMapBetweenTupleAndList() {
+ Map> postsPerTypeAndAuthor = posts.stream()
+ .collect(groupingBy(post -> new Tuple(post.getType(), post.getAuthor())));
+
+ List 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");
+ }
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingCommonsEmptyIfNullUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingCommonsEmptyIfNullUnitTest.java
new file mode 100644
index 0000000000..12f9fcca48
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingCommonsEmptyIfNullUnitTest.java
@@ -0,0 +1,41 @@
+package com.ossez.nullsafecollectionstreams;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.stream.Stream;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+
+public class NullSafeCollectionStreamsUsingCommonsEmptyIfNullUnitTest {
+
+ private final NullSafeCollectionStreamsUsingCommonsEmptyIfNull instance =
+ new NullSafeCollectionStreamsUsingCommonsEmptyIfNull();
+
+ @Test
+ public void whenCollectionIsNull_thenExpectAnEmptyStream() {
+ Collection collection = null;
+ Stream expResult = Stream.empty();
+ Stream result = instance.collectionAsStream(collection);
+ assertStreamEquals(expResult, result);
+
+ }
+
+ @Test
+ public void whenCollectionHasElements_thenExpectAStreamOfExactlyTheSameElements() {
+
+ Collection collection = Arrays.asList("a", "b", "c");
+ Stream expResult = Arrays.stream(new String[] { "a", "b", "c" });
+ Stream result = instance.collectionAsStream(collection);
+ assertStreamEquals(expResult, result);
+ }
+
+ private static void assertStreamEquals(Stream> s1, Stream> s2) {
+ Iterator> iter1 = s1.iterator(), iter2 = s2.iterator();
+ while (iter1.hasNext() && iter2.hasNext())
+ assertEquals(iter1.next(), iter2.next());
+ assert !iter1.hasNext() && !iter2.hasNext();
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingJava8OptionalContainerUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingJava8OptionalContainerUnitTest.java
new file mode 100644
index 0000000000..8497e63f80
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingJava8OptionalContainerUnitTest.java
@@ -0,0 +1,50 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.ossez.nullsafecollectionstreams;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+/**
+ *
+ * @author Kwaje Anthony
+ */
+public class NullSafeCollectionStreamsUsingJava8OptionalContainerUnitTest {
+
+ private final NullSafeCollectionStreamsUsingJava8OptionalContainer instance = new NullSafeCollectionStreamsUsingJava8OptionalContainer();
+
+ @Test
+ public void whenCollectionIsNull_thenExpectAnEmptyStream() {
+ Collection collection = null;
+ Stream expResult = Stream.empty();
+ Stream result = instance.collectionAsStream(collection);
+ assertStreamEquals(expResult, result);
+
+ }
+
+ @Test
+ public void whenCollectionHasElements_thenExpectAStreamOfExactlyTheSameElements() {
+
+ Collection collection = Arrays.asList("a", "b", "c");
+ Stream expResult = Arrays.stream(new String[] { "a", "b", "c" });
+ Stream result = instance.collectionAsStream(collection);
+ assertStreamEquals(expResult, result);
+ }
+
+ private static void assertStreamEquals(Stream> s1, Stream> s2) {
+ Iterator> iter1 = s1.iterator(), iter2 = s2.iterator();
+ while (iter1.hasNext() && iter2.hasNext())
+ assertEquals(iter1.next(), iter2.next());
+ assert !iter1.hasNext() && !iter2.hasNext();
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingNullDereferenceCheckUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingNullDereferenceCheckUnitTest.java
new file mode 100644
index 0000000000..4cd3fc6539
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/nullsafecollectionstreams/NullSafeCollectionStreamsUsingNullDereferenceCheckUnitTest.java
@@ -0,0 +1,45 @@
+
+package com.ossez.nullsafecollectionstreams;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.stream.Stream;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Kwaje Anthony
+ */
+public class NullSafeCollectionStreamsUsingNullDereferenceCheckUnitTest {
+
+ private final NullSafeCollectionStreamsUsingNullDereferenceCheck instance =
+ new NullSafeCollectionStreamsUsingNullDereferenceCheck();
+
+ @Test
+ public void whenCollectionIsNull_thenExpectAnEmptyStream() {
+ Collection collection = null;
+ Stream expResult = Stream.empty();
+ Stream result = instance.collectionAsStream(collection);
+ assertStreamEquals(expResult, result);
+
+ }
+
+ @Test
+ public void whenCollectionHasElements_thenExpectAStreamOfExactlyTheSameElements() {
+
+ Collection collection = Arrays.asList("a", "b", "c");
+ Stream expResult = Arrays.stream(new String[] { "a", "b", "c" });
+ Stream result = instance.collectionAsStream(collection);
+ assertStreamEquals(expResult, result);
+ }
+
+ private static void assertStreamEquals(Stream> s1, Stream> s2) {
+ Iterator> iter1 = s1.iterator(), iter2 = s2.iterator();
+ while (iter1.hasNext() && iter2.hasNext())
+ assertEquals(iter1.next(), iter2.next());
+ assert !iter1.hasNext() && !iter2.hasNext();
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/spliteratorAPI/ExecutorUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/spliteratorAPI/ExecutorUnitTest.java
new file mode 100644
index 0000000000..380aa1f729
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/spliteratorAPI/ExecutorUnitTest.java
@@ -0,0 +1,44 @@
+package com.ossez.spliteratorAPI;
+
+import java.util.Arrays;
+import java.util.Spliterator;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import static org.assertj.core.api.Assertions.*;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ExecutorUnitTest {
+ Article article;
+ Stream stream;
+ Spliterator spliterator;
+ Spliterator split1;
+ Spliterator split2;
+
+ @Before
+ public void init() {
+ article = new Article(Arrays.asList(new Author("Ahmad", 0), new Author("Eugen", 0), new Author("Alice", 1),
+ new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0),
+ new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0),
+ new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1),
+ new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1),
+ new Author("Mike", 0), new Author("Michał", 0), new Author("Loredana", 1)), 0);
+ stream = article.getListOfAuthors().stream();
+ split1 = Executor.generateElements().spliterator();
+ split2 = split1.trySplit();
+ spliterator = new RelatedAuthorSpliterator(article.getListOfAuthors());
+ }
+
+ @Test
+ public void givenAstreamOfAuthors_whenProcessedInParallelWithCustomSpliterator_coubtProducessRightOutput() {
+ Stream stream2 = StreamSupport.stream(spliterator, true);
+ assertThat(Executor.countAutors(stream2.parallel())).isEqualTo(9);
+ }
+
+ @Test
+ public void givenSpliterator_whenAppliedToAListOfArticle_thenSplittedInHalf() {
+ assertThat(new Task(split1).call()).containsSequence(Executor.generateElements().size() / 2 + "");
+ assertThat(new Task(split2).call()).containsSequence(Executor.generateElements().size() / 2 + "");
+ }
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/strategy/StrategyDesignPatternUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/strategy/StrategyDesignPatternUnitTest.java
new file mode 100644
index 0000000000..d10e283568
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/strategy/StrategyDesignPatternUnitTest.java
@@ -0,0 +1,72 @@
+package com.ossez.strategy;
+
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class StrategyDesignPatternUnitTest {
+ @Test
+ public void shouldDivideByTwo_WhenApplyingStaffDiscounter() {
+ Discounter staffDiscounter = new EasterDiscounter();
+
+ final BigDecimal discountedValue = staffDiscounter
+ .apply(BigDecimal.valueOf(100));
+
+ assertThat(discountedValue)
+ .isEqualByComparingTo(BigDecimal.valueOf(50));
+ }
+
+ @Test
+ public void shouldDivideByTwo_WhenApplyingStaffDiscounterWithAnonyousTypes() {
+ Discounter staffDiscounter = new Discounter() {
+ @Override
+ public BigDecimal apply(BigDecimal amount) {
+ return amount.multiply(BigDecimal.valueOf(0.5));
+ }
+ };
+
+ final BigDecimal discountedValue = staffDiscounter
+ .apply(BigDecimal.valueOf(100));
+
+ assertThat(discountedValue)
+ .isEqualByComparingTo(BigDecimal.valueOf(50));
+ }
+
+ @Test
+ public void shouldDivideByTwo_WhenApplyingStaffDiscounterWithLamda() {
+ Discounter staffDiscounter = amount -> amount.multiply(BigDecimal.valueOf(0.5));
+
+ final BigDecimal discountedValue = staffDiscounter
+ .apply(BigDecimal.valueOf(100));
+
+ assertThat(discountedValue)
+ .isEqualByComparingTo(BigDecimal.valueOf(50));
+ }
+
+ @Test
+ public void shouldApplyAllDiscounts() {
+ List discounters = Arrays.asList(Discounter.christmas(), Discounter.newYear(), Discounter.easter());
+
+ BigDecimal amount = BigDecimal.valueOf(100);
+
+ final Discounter combinedDiscounter = discounters
+ .stream()
+ .reduce(v -> v, Discounter::combine);
+
+ combinedDiscounter.apply(amount);
+ }
+
+ @Test
+ public void shouldChainDiscounters() {
+ final Function combinedDiscounters = Discounter
+ .christmas()
+ .andThen(Discounter.newYear());
+
+ combinedDiscounters.apply(BigDecimal.valueOf(100));
+ }
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/streamreduce/tests/StreamReduceManualTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/streamreduce/tests/StreamReduceManualTest.java
new file mode 100644
index 0000000000..28b184338d
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/streamreduce/tests/StreamReduceManualTest.java
@@ -0,0 +1,153 @@
+package com.ossez.streamreduce.tests;
+
+import com.ossez.streamreduce.entities.Rating;
+import com.ossez.streamreduce.entities.Review;
+import com.ossez.streamreduce.entities.User;
+import com.ossez.streamreduce.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 StreamReduceManualTest {
+
+ @Test
+ public void givenIntegerList_whenReduceWithSumAccumulatorLambda_thenCorrect() {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+
+ int result = numbers.stream().reduce(0, (a, b) -> a + b);
+
+ 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("", (a, b) -> a + b);
+
+ 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("", (a, b) -> a.toUpperCase() + b.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 givenUserList_whenReduceWithGreaterAgeAccumulator_thenFindsOldest() {
+ List users = Arrays.asList(new User("John", 30), new User("Alex", 40), new User("Julie", 35));
+
+ User oldest = users.stream().reduce(users.get(0), (user1, user2) -> user1.getAge() >= user2.getAge() ? user1 : user2);
+
+ assertThat(oldest).isEqualTo(users.get(1));
+ }
+
+ @Test
+ public void givenUserListWithRatings_whenReduceWithGreaterAgeAccumulator_thenFindsOldest() {
+ User john = new User("John", 30);
+ john.getRating().add(new Review(5, ""));
+ john.getRating().add(new Review(3, "not bad"));
+ User julie = new User("Julie", 35);
+ john.getRating().add(new Review(4, "great!"));
+ john.getRating().add(new Review(2, "terrible experience"));
+ john.getRating().add(new Review(4, ""));
+ List users = Arrays.asList(john, julie);
+
+ Rating averageRating = users.stream().reduce(new Rating(), (rating, user) -> Rating.average(rating, user.getRating()), Rating::average);
+
+ assertThat(averageRating.getPoints()).isEqualTo(3.6);
+ }
+
+ @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 givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlockAndListContainsZero_thenCorrect() {
+ List numbers = Arrays.asList(0, 1, 2, 3, 4, 5, 6);
+
+ assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 1)).isEqualTo(21);
+ }
+
+ @Test
+ public void givenNumberUtilsClass_whenCalledDivideListElementsWithExtractedTryCatchBlockAndDividerIsZero_thenCorrect() {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+
+ assertThat(NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 0)).isEqualTo(0);
+ }
+
+ @Test
+ public void givenStream_whneCalleddivideListElementsWithApplyFunctionMethod_thenCorrect() {
+ List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
+
+ assertThat(NumberUtils.divideListElementsWithApplyFunctionMethod(numbers, 1)).isEqualTo(21);
+ }
+
+ @Test
+ public void givenTwoStreams_whenCalledReduceOnParallelizedStream_thenFasterExecutionTime() {
+ List userList = new ArrayList<>();
+ for (int i = 0; i <= 1000000; i++) {
+ userList.add(new User("John" + i, i));
+ }
+ long currentTime1 = System.currentTimeMillis();
+ userList.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ long sequentialExecutionTime = System.currentTimeMillis() -currentTime1;
+ long currentTime2 = System.currentTimeMillis();
+ userList.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
+ long parallelizedExecutionTime = System.currentTimeMillis() - currentTime2;
+
+ assertThat(parallelizedExecutionTime).isLessThan(sequentialExecutionTime);
+ }
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/typeinference/TypeInferenceUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/typeinference/TypeInferenceUnitTest.java
new file mode 100644
index 0000000000..829a7c98a0
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/typeinference/TypeInferenceUnitTest.java
@@ -0,0 +1,87 @@
+package com.ossez.typeinference;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+
+public class TypeInferenceUnitTest {
+
+ @Test
+ public void givenNoTypeInference_whenInvokingGenericMethodsWithTypeParameters_ObjectsAreCreated() {
+ // Without type inference. code is verbose.
+ Map> mapOfMaps = new HashMap>();
+ List strList = Collections. emptyList();
+ List intList = Collections. emptyList();
+
+ assertTrue(mapOfMaps.isEmpty());
+ assertTrue(strList.isEmpty());
+ assertTrue(intList.isEmpty());
+ }
+
+ @Test
+ public void givenTypeInference_whenInvokingGenericMethodsWithoutTypeParameters_ObjectsAreCreated() {
+ // With type inference. code is concise.
+ List strListInferred = Collections.emptyList();
+ List intListInferred = Collections.emptyList();
+
+ assertTrue(strListInferred.isEmpty());
+ assertTrue(intListInferred.isEmpty());
+ }
+
+ @Test
+ public void givenJava7_whenInvokingCostructorWithoutTypeParameters_ObjectsAreCreated() {
+ // Type Inference for constructor using diamond operator.
+ Map> mapOfMapsInferred = new HashMap<>();
+
+ assertTrue(mapOfMapsInferred.isEmpty());
+ assertEquals("public class java.util.HashMap", mapOfMapsInferred.getClass()
+ .toGenericString());
+ }
+
+ static List add(List list, T a, T b) {
+ list.add(a);
+ list.add(b);
+ return list;
+ }
+
+ @Test
+ public void givenGenericMethod_WhenInvokedWithoutExplicitTypes_TypesAreInferred() {
+ // Generalized target-type inference
+ List strListGeneralized = add(new ArrayList<>(), "abc", "def");
+ List intListGeneralized = add(new ArrayList<>(), 1, 2);
+ List numListGeneralized = add(new ArrayList<>(), 1, 2.0);
+
+ assertEquals("public class java.util.ArrayList", strListGeneralized.getClass()
+ .toGenericString());
+ assertFalse(intListGeneralized.isEmpty());
+ assertEquals(2, numListGeneralized.size());
+ }
+
+ @Test
+ public void givenLambdaExpressions_whenParameterTypesNotSpecified_ParameterTypesAreInferred() {
+ // Type Inference and Lambda Expressions.
+ List intList = Arrays.asList(5, 3, 4, 2, 1);
+ Collections.sort(intList, (a, b) -> {
+ assertEquals("java.lang.Integer", a.getClass().getName());
+ return a.compareTo(b);
+ });
+ assertEquals("[1, 2, 3, 4, 5]", Arrays.toString(intList.toArray()));
+
+ List strList = Arrays.asList("Red", "Blue", "Green");
+ Collections.sort(strList, (a, b) -> {
+ assertEquals("java.lang.String", a.getClass().getName());
+ return a.compareTo(b);
+ });
+ assertEquals("[Blue, Green, Red]", Arrays.toString(strList.toArray()));
+ }
+
+}
diff --git a/core-java-modules/core-java-8/src/test/java/com/ossez/util/CurrentDateTimeUnitTest.java b/core-java-modules/core-java-8/src/test/java/com/ossez/util/CurrentDateTimeUnitTest.java
new file mode 100644
index 0000000000..ce4e29aeb7
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/java/com/ossez/util/CurrentDateTimeUnitTest.java
@@ -0,0 +1,42 @@
+package com.ossez.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoField;
+
+import org.junit.Test;
+
+public class CurrentDateTimeUnitTest {
+
+ private static final Clock clock = Clock.fixed(Instant.parse("2016-10-09T15:10:30.00Z"), ZoneId.of("UTC"));
+
+ @Test
+ public void shouldReturnCurrentDate() {
+ final LocalDate now = LocalDate.now(clock);
+
+ assertEquals(9, now.get(ChronoField.DAY_OF_MONTH));
+ assertEquals(10, now.get(ChronoField.MONTH_OF_YEAR));
+ assertEquals(2016, now.get(ChronoField.YEAR));
+ }
+
+ @Test
+ public void shouldReturnCurrentTime() {
+ final LocalTime now = LocalTime.now(clock);
+
+ assertEquals(15, now.get(ChronoField.HOUR_OF_DAY));
+ assertEquals(10, now.get(ChronoField.MINUTE_OF_HOUR));
+ assertEquals(30, now.get(ChronoField.SECOND_OF_MINUTE));
+ }
+
+ @Test
+ public void shouldReturnCurrentTimestamp() {
+ final Instant now = Instant.now(clock);
+
+ assertEquals(clock.instant().getEpochSecond(), now.getEpochSecond());
+ }
+}
diff --git a/core-java-modules/core-java-8/src/test/resources/.gitignore b/core-java-modules/core-java-8/src/test/resources/.gitignore
new file mode 100644
index 0000000000..83c05e60c8
--- /dev/null
+++ b/core-java-modules/core-java-8/src/test/resources/.gitignore
@@ -0,0 +1,13 @@
+*.class
+
+#folders#
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/core-java-modules/core-java-annotations/pom.xml b/core-java-modules/core-java-annotations/pom.xml
index 9a21ed8b3b..73290bb025 100644
--- a/core-java-modules/core-java-annotations/pom.xml
+++ b/core-java-modules/core-java-annotations/pom.xml
@@ -3,15 +3,15 @@
4.0.0
com.ossez
core-java-annotations
- 0.1.0-SNAPSHOT
+ ${project.parent.version}
core-java-annotations
jar
- com.ossez
- parent-java
- 0.0.1-SNAPSHOT
- ../../parent-java
+ com.ossez.core-java-modules
+ core-java-modules
+ 0.0.2-SNAPSHOT
+
@@ -73,7 +73,7 @@
- 3.6.1
+ 3.17.2
1.8.9
1.19
1.19
diff --git a/core-java-modules/core-java-collections-list/README.md b/core-java-modules/core-java-collections-list/README.md
new file mode 100644
index 0000000000..ff7a9876a2
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/README.md
@@ -0,0 +1,15 @@
+## Core Java Collections List
+
+This module contains articles about the Java List collection
+
+### Relevant Articles:
+- [Java – Get Random Item/Element From a List](http://www.baeldung.com/java-random-list-element)
+- [Removing all nulls from a List in Java](http://www.baeldung.com/java-remove-nulls-from-list)
+- [Removing all duplicates from a List in Java](http://www.baeldung.com/java-remove-duplicates-from-list)
+- [How to TDD a List Implementation in Java](http://www.baeldung.com/java-test-driven-list)
+- [Iterating Backward Through a List](http://www.baeldung.com/java-list-iterate-backwards)
+- [Remove the First Element from a List](http://www.baeldung.com/java-remove-first-element-from-list)
+- [How to Find an Element in a List with Java](http://www.baeldung.com/find-list-element-java)
+- [Finding Max/Min of a List or Collection](http://www.baeldung.com/java-collection-min-max)
+- [Remove All Occurrences of a Specific Value from a List](https://www.baeldung.com/java-remove-value-from-list)
+- [[Next -->]](/core-java-modules/core-java-collections-list-2)
diff --git a/core-java-modules/core-java-collections-list/pom.xml b/core-java-modules/core-java-collections-list/pom.xml
new file mode 100644
index 0000000000..d62275ab6d
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+ core-java-collections-list
+ 0.1.0-SNAPSHOT
+ core-java-collections-list
+ jar
+
+
+ com.ossez.core-java-modules
+ core-java-modules
+ 0.0.2-SNAPSHOT
+
+
+
+
+
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+
+
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/findanelement/Customer.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/findanelement/Customer.java
new file mode 100644
index 0000000000..3052f92adc
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/findanelement/Customer.java
@@ -0,0 +1,37 @@
+package com.ossez.findanelement;
+
+public class Customer {
+
+ private int id;
+ private String name;
+
+ public Customer(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ return id * 20;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Customer) {
+ Customer otherCustomer = (Customer) obj;
+ if (id == otherCustomer.id)
+ return true;
+ }
+ return false;
+ }
+
+
+}
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/findanelement/FindACustomerInGivenList.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/findanelement/FindACustomerInGivenList.java
new file mode 100644
index 0000000000..c44f1e5209
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/findanelement/FindACustomerInGivenList.java
@@ -0,0 +1,77 @@
+package com.ossez.findanelement;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.collections4.IterableUtils;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+public class FindACustomerInGivenList {
+
+ public Customer findUsingGivenIndex(int indexOfCustomer, List customers) {
+ if (indexOfCustomer >= 0 && indexOfCustomer < customers.size())
+ return customers.get(indexOfCustomer);
+ return null;
+ }
+
+ public int findUsingIndexOf(Customer customer, List customers) {
+ return customers.indexOf(customer);
+ }
+
+ public boolean findUsingContains(Customer customer, List customers) {
+ return customers.contains(customer);
+ }
+
+ public Customer findUsingIterator(String name, List customers) {
+ Iterator iterator = customers.iterator();
+ while (iterator.hasNext()) {
+ Customer customer = iterator.next();
+ if (customer.getName().equals(name)) {
+ return customer;
+ }
+ }
+ return null;
+ }
+
+ public Customer findUsingEnhancedForLoop(String name, List customers) {
+ for (Customer customer : customers) {
+ if (customer.getName().equals(name)) {
+ return customer;
+ }
+ }
+ return null;
+ }
+
+ public Customer findUsingStream(String name, List customers) {
+ return customers.stream()
+ .filter(customer -> customer.getName().equals(name))
+ .findFirst()
+ .orElse(null);
+ }
+
+ public Customer findUsingParallelStream(String name, List customers) {
+ return customers.parallelStream()
+ .filter(customer -> customer.getName().equals(name))
+ .findAny()
+ .orElse(null);
+ }
+
+ public Customer findUsingGuava(String name, List customers) {
+ return Iterables.tryFind(customers, new Predicate() {
+ public boolean apply(Customer customer) {
+ return customer.getName().equals(name);
+ }
+ }).orNull();
+ }
+
+ public Customer findUsingApacheCommon(String name, List customers) {
+ return IterableUtils.find(customers, new org.apache.commons.collections4.Predicate() {
+ public boolean evaluate(Customer customer) {
+ return customer.getName().equals(name);
+ }
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java/list/CustomList.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java/list/CustomList.java
new file mode 100644
index 0000000000..04848e5452
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java/list/CustomList.java
@@ -0,0 +1,210 @@
+package com.ossez.java.list;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+public class CustomList implements List {
+ private Object[] internal = {};
+
+ @Override
+ public boolean isEmpty() {
+ // the first cycle
+ // return true;
+
+ // the second cycle
+ // if (internal.length != 0) {
+ // return false;
+ // } else {
+ // return true;
+ // }
+
+ // refactoring
+ return internal.length == 0;
+ }
+
+ @Override
+ public int size() {
+ // the first cycle
+ // if (isEmpty()) {
+ // return 0;
+ // } else {
+ // return internal.length;
+ // }
+
+ // refactoring
+ return internal.length;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public E get(int index) {
+ // the first cycle
+ // return (E) internal[0];
+
+ // improvement
+ return (E) internal[index];
+ }
+
+ @Override
+ public boolean add(E element) {
+ // the first cycle
+ // internal = new Object[] { element };
+ // return true;
+
+ // the second cycle
+ Object[] temp = Arrays.copyOf(internal, internal.length + 1);
+ temp[internal.length] = element;
+ internal = temp;
+ return true;
+ }
+
+ @Override
+ public void add(int index, E element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean addAll(Collection extends E> collection) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean addAll(int index, Collection extends E> collection) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public E remove(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean remove(Object object) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeAll(Collection> collection) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean retainAll(Collection> collection) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean contains(Object object) {
+ for (Object element : internal) {
+ if (object.equals(element)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean containsAll(Collection> collection) {
+ for (Object element : collection)
+ if (!contains(element)) {
+ return false;
+ }
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public E set(int index, E element) {
+ E oldElement = (E) internal[index];
+ internal[index] = element;
+ return oldElement;
+ }
+
+ @Override
+ public void clear() {
+ internal = new Object[0];
+ }
+
+ @Override
+ public int indexOf(Object object) {
+ for (int i = 0; i < internal.length; i++) {
+ if (object.equals(internal[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public int lastIndexOf(Object object) {
+ for (int i = internal.length - 1; i >= 0; i--) {
+ if (object.equals(internal[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List subList(int fromIndex, int toIndex) {
+ Object[] temp = new Object[toIndex - fromIndex];
+ System.arraycopy(internal, fromIndex, temp, 0, temp.length);
+ return (List) Arrays.asList(temp);
+ }
+
+ @Override
+ public Object[] toArray() {
+ return Arrays.copyOf(internal, internal.length);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public T[] toArray(T[] array) {
+ if (array.length < internal.length) {
+ return (T[]) Arrays.copyOf(internal, internal.length, array.getClass());
+ }
+
+ System.arraycopy(internal, 0, array, 0, internal.length);
+ if (array.length > internal.length) {
+ array[internal.length] = null;
+ }
+ return array;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new CustomIterator();
+ }
+
+ @Override
+ public ListIterator listIterator() {
+ return null;
+ }
+
+ @Override
+ public ListIterator listIterator(int index) {
+ // ignored for brevity
+ return null;
+ }
+
+ private class CustomIterator implements Iterator {
+ int index;
+
+ @Override
+ public boolean hasNext() {
+ return index != internal.length;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public E next() {
+ E element = (E) CustomList.this.internal[index];
+ index++;
+ return element;
+ }
+ }
+}
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java/list/ReverseIterator.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java/list/ReverseIterator.java
new file mode 100644
index 0000000000..eb8c0e4f16
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java/list/ReverseIterator.java
@@ -0,0 +1,80 @@
+package com.ossez.java.list;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.commons.collections4.iterators.ReverseListIterator;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Provides methods for iterating backward over a list.
+ */
+public class ReverseIterator {
+
+ /**
+ * Iterate using the for loop.
+ *
+ * @param list the list
+ */
+ public void iterateUsingForLoop(final List list) {
+
+ for (int i = list.size(); i-- > 0; ) {
+ System.out.println(list.get(i));
+ }
+ }
+
+ /**
+ * Iterate using the Java {@link ListIterator}.
+ *
+ * @param list the list
+ */
+ public void iterateUsingListIterator(final List list) {
+
+ final ListIterator listIterator = list.listIterator(list.size());
+ while (listIterator.hasPrevious()) {
+ System.out.println(listIterator.previous());
+ }
+ }
+
+ /**
+ * Iterate using Java {@link Collections} API.
+ *
+ * @param list the list
+ */
+ public void iterateUsingCollections(final List list) {
+
+ Collections.reverse(list);
+ for (final String item : list) {
+ System.out.println(item);
+ }
+ }
+
+ /**
+ * Iterate using Apache Commons {@link ReverseListIterator}.
+ *
+ * @param list the list
+ */
+ public void iterateUsingApacheReverseListIterator(final List list) {
+
+ final ReverseListIterator listIterator = new ReverseListIterator(list);
+ while (listIterator.hasNext()) {
+ System.out.println(listIterator.next());
+ }
+ }
+
+ /**
+ * Iterate using Guava {@link Lists} API.
+ *
+ * @param list the list
+ */
+ public void iterateUsingGuava(final List list) {
+
+ final List reversedList = Lists.reverse(list);
+ for (final String item : reversedList) {
+ System.out.println(item);
+ }
+ }
+
+}
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java_8_features/Car.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java_8_features/Car.java
new file mode 100644
index 0000000000..8dc0db89ba
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java_8_features/Car.java
@@ -0,0 +1,31 @@
+package com.ossez.java_8_features;
+
+public class Car {
+
+ private String model;
+ private int topSpeed;
+
+ public Car(String model, int topSpeed) {
+ super();
+ this.model = model;
+ this.topSpeed = topSpeed;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public int getTopSpeed() {
+ return topSpeed;
+ }
+
+ public void setTopSpeed(int topSpeed) {
+ this.topSpeed = topSpeed;
+ }
+
+
+}
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java_8_features/Person.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java_8_features/Person.java
new file mode 100644
index 0000000000..5675c86006
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/java_8_features/Person.java
@@ -0,0 +1,27 @@
+package com.ossez.java_8_features;
+
+public class Person {
+ private String name;
+ private Integer age;
+
+ public Person(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/Flower.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/Flower.java
new file mode 100644
index 0000000000..81443acdd6
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/Flower.java
@@ -0,0 +1,28 @@
+package com.ossez.list;
+
+public class Flower {
+
+ private String name;
+ private int petals;
+
+ public Flower(String name, int petals) {
+ this.name = name;
+ this.petals = petals;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getPetals() {
+ return petals;
+ }
+
+ public void setPetals(int petals) {
+ this.petals = petals;
+ }
+}
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Pen.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Pen.java
new file mode 100644
index 0000000000..d5f578ad20
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Pen.java
@@ -0,0 +1,18 @@
+package com.ossez.list.listoflist;
+
+public class Pen implements Stationery {
+
+ public String name;
+
+ public Pen(String name) {
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Pencil.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Pencil.java
new file mode 100644
index 0000000000..f43abc5885
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Pencil.java
@@ -0,0 +1,18 @@
+package com.ossez.list.listoflist;
+
+public class Pencil implements Stationery{
+
+ public String name;
+
+ public Pencil(String name) {
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Rubber.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Rubber.java
new file mode 100644
index 0000000000..a1a57822d2
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Rubber.java
@@ -0,0 +1,18 @@
+package com.ossez.list.listoflist;
+
+public class Rubber implements Stationery {
+
+ public String name;
+
+ public Rubber(String name) {
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Stationery.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Stationery.java
new file mode 100644
index 0000000000..cb08770f79
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/listoflist/Stationery.java
@@ -0,0 +1,5 @@
+package com.ossez.list.listoflist;
+
+public interface Stationery {
+
+}
diff --git a/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/removeall/RemoveAll.java b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/removeall/RemoveAll.java
new file mode 100644
index 0000000000..868b9483cc
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/java/com/ossez/list/removeall/RemoveAll.java
@@ -0,0 +1,111 @@
+package com.ossez.list.removeall;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class RemoveAll {
+
+ static void removeWithWhileLoopPrimitiveElement(List list, int element) {
+ while (list.contains(element)) {
+ list.remove(element);
+ }
+ }
+
+ static void removeWithWhileLoopNonPrimitiveElement(List list, Integer element) {
+ while (list.contains(element)) {
+ list.remove(element);
+ }
+ }
+
+ static void removeWithWhileLoopStoringFirstOccurrenceIndex(List list, Integer element) {
+ int index;
+ while ((index = list.indexOf(element)) >= 0) {
+ list.remove(index);
+ }
+ }
+
+ static void removeWithCallingRemoveUntilModifies(List list, Integer element) {
+ while (list.remove(element))
+ ;
+ }
+
+ static void removeWithStandardForLoopUsingIndex(List list, int element) {
+ for (int i = 0; i < list.size(); i++) {
+ if (Objects.equals(element, list.get(i))) {
+ list.remove(i);
+ }
+ }
+ }
+
+ static void removeWithForLoopDecrementOnRemove(List list, int element) {
+ for (int i = 0; i < list.size(); i++) {
+ if (Objects.equals(element, list.get(i))) {
+ list.remove(i);
+ i--;
+ }
+ }
+ }
+
+ static void removeWithForLoopIncrementIfRemains(List list, int element) {
+ for (int i = 0; i < list.size();) {
+ if (Objects.equals(element, list.get(i))) {
+ list.remove(i);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ static void removeWithForEachLoop(List list, int element) {
+ for (Integer number : list) {
+ if (Objects.equals(number, element)) {
+ list.remove(number);
+ }
+ }
+ }
+
+ static void removeWithIterator(List list, int element) {
+ for (Iterator i = list.iterator(); i.hasNext();) {
+ Integer number = i.next();
+ if (Objects.equals(number, element)) {
+ i.remove();
+ }
+ }
+ }
+
+ static List removeWithCollectingAndReturningRemainingElements(List list, int element) {
+ List remainingElements = new ArrayList<>();
+ for (Integer number : list) {
+ if (!Objects.equals(number, element)) {
+ remainingElements.add(number);
+ }
+ }
+ return remainingElements;
+ }
+
+ static void removeWithCollectingRemainingElementsAndAddingToOriginalList(List list, int element) {
+ List remainingElements = new ArrayList<>();
+ for (Integer number : list) {
+ if (!Objects.equals(number, element)) {
+ remainingElements.add(number);
+ }
+ }
+
+ list.clear();
+ list.addAll(remainingElements);
+ }
+
+ static List removeWithStreamFilter(List list, Integer element) {
+ return list.stream()
+ .filter(e -> !Objects.equals(e, element))
+ .collect(Collectors.toList());
+ }
+
+ static void removeWithRemoveIf(List list, Integer element) {
+ list.removeIf(n -> Objects.equals(n, element));
+ }
+
+}
diff --git a/core-java-modules/core-java-collections-list/src/main/resources/logback.xml b/core-java-modules/core-java-collections-list/src/main/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-list/src/test/java/com/ossez/collections/JavaCollectionCleanupUnitTest.java b/core-java-modules/core-java-collections-list/src/test/java/com/ossez/collections/JavaCollectionCleanupUnitTest.java
new file mode 100644
index 0000000000..40aa276080
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/test/java/com/ossez/collections/JavaCollectionCleanupUnitTest.java
@@ -0,0 +1,105 @@
+package com.ossez.collections;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsInRelativeOrder;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.PredicateUtils;
+import org.junit.Test;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+public class JavaCollectionCleanupUnitTest {
+
+ // tests - removing nulls
+
+ @Test
+ public void givenListContainsNulls_whenRemovingNullsWithPlainJava_thenCorrect() {
+ final List list = Lists.newArrayList(null, 1, null);
+ while (list.remove(null))
+ ;
+
+ assertThat(list, hasSize(1));
+ }
+
+ @Test
+ public void givenListContainsNulls_whenRemovingNullsWithPlainJavaAlternative_thenCorrect() {
+ final List list = Lists.newArrayList(null, 1, null);
+ list.removeAll(Collections.singleton(null));
+
+ assertThat(list, hasSize(1));
+ }
+
+ @Test
+ public void givenListContainsNulls_whenRemovingNullsWithGuavaV1_thenCorrect() {
+ final List list = Lists.newArrayList(null, 1, null);
+ Iterables.removeIf(list, Predicates.isNull());
+
+ assertThat(list, hasSize(1));
+ }
+
+ @Test
+ public void givenListContainsNulls_whenRemovingNullsWithGuavaV2_thenCorrect() {
+ final List list = Lists.newArrayList(null, 1, null, 2, 3);
+ final List listWithoutNulls = Lists.newArrayList(Iterables.filter(list, Predicates.notNull()));
+
+ assertThat(listWithoutNulls, hasSize(3));
+ }
+
+ @Test
+ public void givenListContainsNulls_whenRemovingNullsWithCommonsCollections_thenCorrect() {
+ final List list = Lists.newArrayList(null, 1, 2, null, 3, null);
+ CollectionUtils.filter(list, PredicateUtils.notNullPredicate());
+
+ assertThat(list, hasSize(3));
+ }
+
+ // tests - remove duplicates
+
+ @Test
+ public void givenListContainsDuplicates_whenRemovingDuplicatesWithPlainJava_thenCorrect() {
+ final List listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
+ final List listWithoutDuplicates = new ArrayList<>(new HashSet<>(listWithDuplicates));
+
+ assertThat(listWithoutDuplicates, hasSize(5));
+ assertThat(listWithoutDuplicates, containsInAnyOrder(5, 0, 3, 1, 2));
+ }
+
+ @Test
+ public void givenListContainsDuplicates_whenRemovingDuplicatesPreservingOrderWithPlainJava_thenCorrect() {
+ final List listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
+ final List listWithoutDuplicates = new ArrayList<>(new LinkedHashSet<>(listWithDuplicates));
+
+ assertThat(listWithoutDuplicates, hasSize(5));
+ assertThat(listWithoutDuplicates, containsInRelativeOrder(5, 0, 3, 1, 2));
+ }
+
+ @Test
+ public void givenListContainsDuplicates_whenRemovingDuplicatesWithGuava_thenCorrect() {
+ final List listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
+ final List listWithoutDuplicates = Lists.newArrayList(Sets.newHashSet(listWithDuplicates));
+
+ assertThat(listWithoutDuplicates, hasSize(5));
+ assertThat(listWithoutDuplicates, containsInAnyOrder(5, 0, 3, 1, 2));
+ }
+
+ @Test
+ public void givenListContainsDuplicates_whenRemovingDuplicatesPreservingOrderWithGuava_thenCorrect() {
+ final List listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
+ final List listWithoutDuplicates = Lists.newArrayList(Sets.newLinkedHashSet(listWithDuplicates));
+
+ assertThat(listWithoutDuplicates, hasSize(5));
+ assertThat(listWithoutDuplicates, containsInRelativeOrder(5, 0, 3, 1, 2));
+ }
+}
diff --git a/core-java-modules/core-java-collections-list/src/test/java/com/ossez/findanelement/FindACustomerInGivenListUnitTest.java b/core-java-modules/core-java-collections-list/src/test/java/com/ossez/findanelement/FindACustomerInGivenListUnitTest.java
new file mode 100644
index 0000000000..2bd27b5fb6
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/test/java/com/ossez/findanelement/FindACustomerInGivenListUnitTest.java
@@ -0,0 +1,158 @@
+package com.ossez.findanelement;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+public class FindACustomerInGivenListUnitTest {
+
+ private static List customers = new ArrayList<>();
+
+ static {
+ customers.add(new Customer(1, "Jack"));
+ customers.add(new Customer(2, "James"));
+ customers.add(new Customer(3, "Sam"));
+ }
+
+ private static FindACustomerInGivenList findACustomerInGivenList = new FindACustomerInGivenList();
+
+ @Test
+ public void givenAnIndex_whenFoundUsingGivenIndex_thenReturnCustomer() {
+ Customer customer = findACustomerInGivenList.findUsingGivenIndex(0, customers);
+
+ assertEquals(1, customer.getId());
+ }
+
+ @Test
+ public void givenAnIndex_whenNotFoundUsingGivenIndex_thenReturnNull() {
+ Customer customer = findACustomerInGivenList.findUsingGivenIndex(5, customers);
+
+ assertNull(customer);
+ }
+
+ @Test
+ public void givenACustomer_whenFoundUsingContains_thenReturnTrue() {
+ Customer james = new Customer(2, "James");
+ boolean isJamesPresent = findACustomerInGivenList.findUsingContains(james, customers);
+
+ assertEquals(true, isJamesPresent);
+ }
+
+ @Test
+ public void givenACustomer_whenNotFoundUsingContains_thenReturnFalse() {
+ Customer john = new Customer(5, "John");
+ boolean isJohnPresent = findACustomerInGivenList.findUsingContains(john, customers);
+
+ assertEquals(false, isJohnPresent);
+ }
+
+ @Test
+ public void givenACustomer_whenFoundUsingIndexOf_thenReturnItsIndex() {
+ Customer james = new Customer(2, "James");
+ int indexOfJames = findACustomerInGivenList.findUsingIndexOf(james, customers);
+
+ assertEquals(1, indexOfJames);
+ }
+
+ @Test
+ public void givenACustomer_whenNotFoundUsingIndexOf_thenReturnMinus1() {
+ Customer john = new Customer(5, "John");
+ int indexOfJohn = findACustomerInGivenList.findUsingIndexOf(john, customers);
+
+ assertEquals(-1, indexOfJohn);
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameFoundUsingIterator_thenReturnCustomer() {
+ Customer james = findACustomerInGivenList.findUsingIterator("James", customers);
+
+ assertEquals("James", james.getName());
+ assertEquals(2, james.getId());
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameNotFoundUsingIterator_thenReturnNull() {
+ Customer john = findACustomerInGivenList.findUsingIterator("John", customers);
+
+ assertNull(john);
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameFoundUsingEnhancedFor_thenReturnCustomer() {
+ Customer james = findACustomerInGivenList.findUsingEnhancedForLoop("James", customers);
+
+ assertEquals("James", james.getName());
+ assertEquals(2, james.getId());
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameNotFoundUsingEnhancedFor_thenReturnNull() {
+ Customer john = findACustomerInGivenList.findUsingEnhancedForLoop("John", customers);
+
+ assertNull(john);
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameFoundUsingStream_thenReturnCustomer() {
+ Customer james = findACustomerInGivenList.findUsingStream("James", customers);
+
+ assertEquals("James", james.getName());
+ assertEquals(2, james.getId());
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameNotFoundUsingStream_thenReturnNull() {
+ Customer john = findACustomerInGivenList.findUsingStream("John", customers);
+
+ assertNull(john);
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameFoundUsingParallelStream_thenReturnCustomer() {
+ Customer james = findACustomerInGivenList.findUsingParallelStream("James", customers);
+
+ assertEquals("James", james.getName());
+ assertEquals(2, james.getId());
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameNotFoundUsingParallelStream_thenReturnNull() {
+ Customer john = findACustomerInGivenList.findUsingParallelStream("John", customers);
+
+ assertNull(john);
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameFoundUsingApacheCommon_thenReturnCustomer() {
+ Customer james = findACustomerInGivenList.findUsingApacheCommon("James", customers);
+
+ assertEquals("James", james.getName());
+ assertEquals(2, james.getId());
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameNotFoundUsingApacheCommon_thenReturnNull() {
+ Customer john = findACustomerInGivenList.findUsingApacheCommon("John", customers);
+
+ assertNull(john);
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameFoundUsingGuava_thenReturnCustomer() {
+ Customer james = findACustomerInGivenList.findUsingGuava("James", customers);
+
+ assertEquals("James", james.getName());
+ assertEquals(2, james.getId());
+ }
+
+ @Test
+ public void givenName_whenCustomerWithNameNotFoundUsingGuava_thenReturnNull() {
+ Customer john = findACustomerInGivenList.findUsingGuava("John", customers);
+
+ assertNull(john);
+ }
+
+}
diff --git a/core-java-modules/core-java-collections-list/src/test/java/com/ossez/java/list/CustomListUnitTest.java b/core-java-modules/core-java-collections-list/src/test/java/com/ossez/java/list/CustomListUnitTest.java
new file mode 100644
index 0000000000..f9bd490ca1
--- /dev/null
+++ b/core-java-modules/core-java-collections-list/src/test/java/com/ossez/java/list/CustomListUnitTest.java
@@ -0,0 +1,296 @@
+package com.ossez.java.list;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Test;
+
+public class CustomListUnitTest {
+ @Test
+ public void givenEmptyList_whenIsEmpty_thenTrueIsReturned() {
+ List