diff --git a/P/Sda1/Streams/Solution/src/test/java/de/hdm_stuttgart/mi/javastreams/Java8FunctionalTest.java b/P/Sda1/Streams/Solution/src/test/java/de/hdm_stuttgart/mi/javastreams/Java8FunctionalTest.java index 57cee719ce23332aa478ef5a405acade034911a7..3b9d0a1d162d80c7e197df226b9c23c77db5b9de 100644 --- a/P/Sda1/Streams/Solution/src/test/java/de/hdm_stuttgart/mi/javastreams/Java8FunctionalTest.java +++ b/P/Sda1/Streams/Solution/src/test/java/de/hdm_stuttgart/mi/javastreams/Java8FunctionalTest.java @@ -6,6 +6,7 @@ import java.util.*; import java.util.stream.Collector; import java.util.stream.Collectors; +import com.github.npathai.hamcrestopt.OptionalMatchers; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.FixMethodOrder; @@ -25,10 +26,10 @@ public class Java8FunctionalTest { static private final List<Student> students = ImmutableList.of( new Student("Fred", 2, Student.Sex.MALE, "fred@example.com") - ,new Student("Jane", 1, Student.Sex.FEMALE, "jane@kiv.de") - ,new Student("George", 4, Student.Sex.MALE, "george@math.edu") - ,new Student("Bob", 2, Student.Sex.MALE, "bob@uk.edu") - ,new Student("Kim", 2, Student.Sex.FEMALE, "wilde@serious.de") + ,new Student("Jane", 1, Student.Sex.FEMALE, "jane@kiv.de") + ,new Student("George",4, Student.Sex.MALE, "george@math.edu") + ,new Student("Bob", 2, Student.Sex.MALE, "bob@uk.edu") + ,new Student("Kim", 2, Student.Sex.FEMALE, "wilde@serious.de") ); /** @@ -36,11 +37,11 @@ public class Java8FunctionalTest { * names alphabetically ordered eliminating possible duplicates. Implementation hints:</p> * * <pre - * >"Fred", 2, Student.Sex.MALE, "fred@example.com" - * "Jane", 1, Student.Sex.FEMALE, "jane@kiv.de" - * "George", 4, Student.Sex.MALE, "george@math.edu" - * "Bob", 2, Student.Sex.MALE, "bob@uk.edu" - * "Kim", 2, Student.Sex.FEMALE, "wilde@serious.de"</pre> + * >{"Fred", 2, Student.Sex.MALE, "fred@example.com"} + * {"Jane", 1, Student.Sex.FEMALE, "jane@kiv.de"} + * {"George", 4, Student.Sex.MALE, "george@math.edu"} + * {"Bob", 2, Student.Sex.MALE, "bob@uk.edu"} + * {"Kim", 2, Student.Sex.FEMALE, "wilde@serious.de"}</pre> * * <p>Result: {"Bob", "Fred", "George"}</p> */ @@ -48,19 +49,19 @@ public class Java8FunctionalTest { public void allMaleDistinctNameOrderedByEmail() { final List<String> emails = - students.parallelStream(). - filter(s -> s.gender == Sex.MALE). - sorted(Comparator.comparing(Student::getEmailAddress)). - map(Student::getName). - distinct(). - collect(Collectors.toList()); + students.parallelStream(). + filter(s -> s.gender == Sex.MALE). + sorted(Comparator.comparing(Student::getEmailAddress)). + map(Student::getName). + distinct(). + collect(Collectors.toList()); assertThat( - emails, - Matchers.equalTo( - ImmutableList.of("Bob", "Fred", "George") - ) - ); + emails, + Matchers.equalTo( + ImmutableList.of("Bob", "Fred", "George") + ) + ); } /** @@ -80,84 +81,96 @@ public class Java8FunctionalTest { * <dd>Expected value: 1 + 2 == 3</dd> * </dl> * - * <p>Implementation hint: Process a stream of Student instances by:</p> + * <p>Implementation hint: Process a stream of {@link Student} instances by:</p> * * <ol> * <li>Filter students having a german email.</li> - * <li>Map objects to int.</li> + * <li>Map objects to mark values of type int.</li> * <li>Provide a suitable * <a href="https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html#reduce" - * >reduce operation</a>. You may safely assume the existence of at least one Student.</li> + * >reduce operation</a>. You may safely assume the existence of at least one student.</li> * </ol> * - * <p>You may want to read + * <p>You may also want to read * <a href="https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html#reduce" * >https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html#reduce</a>.</p> */ @Test public void markSumAllStudentsMarksHavingEmail_Dot_de() { - Assert.assertEquals( - 3, //Expected marks sum 3 == 1 + 2 - students.parallelStream() - .filter(p -> p.emailAddress.endsWith(".de")) // Jane and Kim - .mapToInt(Student::getMark) - .reduce(0, (a, b) -> a + b) - ); + + final int sumMarksOfStudentsHavingGermanEmail = students.parallelStream() + .filter(p -> p.emailAddress.endsWith(".de")) // Jane and Kim + .mapToInt(Student::getMark) + .reduce(0, (a, b) -> a + b); + + assertThat(sumMarksOfStudentsHavingGermanEmail, Matchers.equalTo(3)); } /** - * <p>A comma separated string containing all students' alphabetically ordered - * email addresses:</p> + * <p>A comma separated string containing all students' alphabetically ordered email addresses:</p> * - * "bob@uk.edu, fred@example.com, george@math.edu, ..." - * + * <p>{"bob@uk.edu, fred@example.com, george@math.edu, ..."}</p> + * + * <p>Implementation hint: Process a stream of {@link Student} instances by:</p> + * + * <ol> + * <li>Map {@link Student} instances to their emails.</li> + * <li>Sort alphabetically.</li> + * <li>Use <a href="https://www.baeldung.com/java-8-collectors">a suitable</a> {@link Collector}.</li> + * </ol> */ @Test public void orderedCharacterSeparatedEmailList() { - Assert.assertEquals( - "bob@uk.edu, fred@example.com, george@math.edu, jane@kiv.de, wilde@serious.de", - - students.parallelStream(). - map(Student::getEmailAddress). - sorted(). - collect(new CsvCollector(", ")) // Using ", " as separator string. - ); + final String csvSortedEmails = students.stream(). + map(Student::getEmailAddress). + sorted(). + collect(Collectors.joining(", ")); + assertThat( + csvSortedEmails, + Matchers.equalTo("bob@uk.edu, fred@example.com, george@math.edu, jane@kiv.de, wilde@serious.de") + ); } /** * Achieves the same result as in {@link #orderedCharacterSeparatedEmailList()} - * internally using a standard collector with a modified - * {@link Collector#finisher()} method: - * - * "bob@uk.edu, fred@example.com, george@math.edu, ..." - * + * internally using <a href="https://www.baeldung.com/java-8-streams#reduction">reduction</a>: + * + * <p>Implementation hint: Process a stream of {@link Student} instances by:</p> + * + * <ol> + * <li>Map {@link Student} instances to their emails.</li> + * <li>Sort alphabetically.</li> + * <li>Implement a suitable reducing operation turning a stream of email adresses into + * a single String containing comma separated email adresses.</li> + * <li>You may safely assume at least one email to be present.</li> + * </ol> */ @Test public void orderedCharacterSeparatedEmailList2() { - Assert.assertEquals( - "bob@uk.edu, fred@example.com, george@math.edu, jane@kiv.de, wilde@serious.de", + final Optional<String> emailCsvList = + students.parallelStream(). + map(Student::getEmailAddress). + sorted(). + reduce((s, t) -> s + ", " + t); - students.parallelStream(). - map(Student::getEmailAddress). - sorted(). - collect - (Collectors.collectingAndThen - (Collectors.toList(), - l -> l.stream(). // A stream within a stream. - reduce((s1, s2) -> s1 + ", " + s2). - get() - ) - ) - ); + assertThat(emailCsvList, OptionalMatchers.isPresentAndIs( + "bob@uk.edu, fred@example.com, george@math.edu, jane@kiv.de, wilde@serious.de")); } /** - * Get the average mark of all female students as double value. - * - * Female marks: {1, 2}, sum == 3, average = 3. / 2 == 1.5 + * <p>Get the average mark of all female students as double value.</p> + * + * <pre + * >{"Jane", 1, Student.Sex.FEMALE, "jane@kiv.de"} + * {"Kim", 2, Student.Sex.FEMALE, "wilde@serious.de"}</pre> + * + * + * <p>Female student marks sum: 1 + 2 == 3</p> + * + * <p>Result: average = 3. / 2 == 1.5</p> * */ @Test @@ -169,48 +182,45 @@ public class Java8FunctionalTest { mapToInt(Student::getMark). average(); + // No suitable matcher on offer Assert.assertTrue(femaleAverage.isPresent()); Assert.assertEquals((1 + 2) / 2., femaleAverage.getAsDouble(), 1.E-20); } /** - * Group students by sex and collect their respective names: + * Create a {@code Map<Student.Sex, List<String>>} grouping students by sex and collecting their respective names: * - * Female: - * "Jane" - * "Kim" - * - * Male: - * "Fred" - * "George" - * "Bob" + * { + * Female: {"Jane", "Kim"}, + * Male: {"Fred", "George", "Bob"} + * } * */ @Test public void studentNamesBySex() { final Map<Student.Sex, List<String>> studentnamesBySex = - students - .parallelStream() + students.parallelStream() .collect( - Collectors.groupingBy( - Student::getSex, - Collectors.mapping( - Student::getName, - Collectors.toList()) - ) - ); + Collectors.groupingBy( + Student::getSex, + Collectors.mapping( + Student::getName, + Collectors.toList() + ) + ) + ); assertThat( - studentnamesBySex, - Matchers.<Map<Student.Sex, List<String>>> equalTo( - ImmutableMap.of ( - Student.Sex.MALE, ImmutableList.of("Fred", "George", "Bob"), - Student.Sex.FEMALE, ImmutableList.of("Jane", "Kim") - ) - ) - ); + studentnamesBySex, + Matchers.equalTo( + ImmutableMap.of ( + Student.Sex.MALE, ImmutableList.of("Fred", "George", "Bob"), + Student.Sex.FEMALE, ImmutableList.of("Jane", "Kim") + ) + ) + ); } /** @@ -219,73 +229,83 @@ public class Java8FunctionalTest { * Mark 1: "Jane" --- 1 student * Mark 2: "Fred", "Bob", "Kim" --- 3 students * Mark 4: "George" --- 1 student + * + * Result: + * + * <pre>{ + * 1: 1, + * 2: 3, + * 4: 1 + * }</pre> * */ @Test public void markingFrequencies() { final Map<Integer, Integer> frequencyByMark = - students - .parallelStream() - .collect( - Collectors.groupingBy( - Student::getMark, - Collectors.reducing( - 0, - s -> 1,// counting heads. - Integer::sum) - ) - ); + students + .parallelStream() + .collect( + Collectors.groupingBy( + Student::getMark, + Collectors.reducing( + 0, + s -> 1, // counting heads. + Integer::sum + ) + ) + ); - assertThat(frequencyByMark, - Matchers.equalTo( - ImmutableMap.of( - 1, 1, - 2, 3, - 4, 1 - ) - ) - ); + assertThat( + frequencyByMark, + Matchers.equalTo( + ImmutableMap.of( + 1, 1, + 2, 3, + 4, 1 + ) + ) + ); } /** - * Students' names in ascending order grouped by by marking category: - * - * Mark 1: {"Jane"} - * Mark 2: {"Bob", "Fred", "Kim"} - * Mark 4: {"George"} + * Students' names as {@code List<String>} in ascending order grouped by by mark values: + * <pre>{ + * 1: {"Jane"} + * 2: {"Bob", "Fred", "Kim"} + * 4: {"George"} + * }</pre> * */ @Test - public void studentnamessByMark() { + public void studentnamesByMark() { final Map<Integer, List<String>> namesByMark = - students - .parallelStream() - .collect( + students.parallelStream(). + collect( Collectors.groupingBy( - Student::getMark, - Collectors.mapping( - Student::getName, - Collectors.collectingAndThen( - Collectors.toList(), - l -> { - Collections.sort(l); - return l; - } - ) - ) - ) - ); + Student::getMark, + Collectors.mapping( + Student::getName, + Collectors.collectingAndThen( + Collectors.toList(), + l -> { + Collections.sort(l); + return l; + } + ) + ) + ) + ); assertThat( - namesByMark, - Matchers.<Map<Integer, List<String>>> equalTo ( - ImmutableMap.of( - 1, ImmutableList.of("Jane"), - 2, ImmutableList.of("Bob", "Fred", "Kim"), - 4, ImmutableList.of("George") - ) - ) - ); + namesByMark, + Matchers.equalTo ( + ImmutableMap.of( + 1, ImmutableList.of("Jane"), + 2, ImmutableList.of("Bob", "Fred", "Kim"), + 4, ImmutableList.of("George") + ) + ) + ); } -} +} \ No newline at end of file