From c152d17eb17be2fa6dd94d74ce2f8fc03d17b034 Mon Sep 17 00:00:00 2001 From: Ken Kousen Date: Wed, 8 Nov 2023 22:29:31 -0700 Subject: [PATCH] Refactor StringExercises and improve tests Refactored StringExercises.java to make better use of stream operations and lambdas. Methods were updated to include tests, confirming their correctness. Additional imports were included to support stream operations, and assertions were added in tests to verify expected behavior. Stream operations are modified in the tests to sort strings and allocate in collections. New tests were also added to enhance the test coverage. These changes support more readable and robust code, while leveraging Java 8 features like lambda expressions and streams to improve the performance. --- src/test/java/streams/StringExercises.java | 83 ++++++++++++++++++---- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/src/test/java/streams/StringExercises.java b/src/test/java/streams/StringExercises.java index 9ac9e25..a5a4197 100644 --- a/src/test/java/streams/StringExercises.java +++ b/src/test/java/streams/StringExercises.java @@ -2,71 +2,130 @@ import org.junit.jupiter.api.Test; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; +import java.util.*; +import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; public class StringExercises { private final List strings = Arrays.asList("this", "is", "a", "list", "of", "strings"); + @SuppressWarnings("Convert2Lambda") @Test public void stringLengthSort_InnerClass() { // Java 5, 6, 7 - strings.sort(new Comparator() { + strings.sort(new Comparator<>() { @Override public int compare(String s1, String s2) { return s1.length() - s2.length(); } }); System.out.println(strings); + assertThat(strings).containsExactly("a", "is", "of", "this", "list", "strings"); } + @SuppressWarnings("ComparatorCombinators") @Test public void stringLengthSort_lambda() { // Use lambda for the Comparator (reverse sort) + strings.sort((s1, s2) -> s2.length() - s1.length()); + System.out.println(strings); // Use the "sorted" method on Stream + List sorted = strings.stream() + .sorted((s1, s2) -> s1.length() - s2.length()) + .toList(); + System.out.println(sorted); + assertThat(sorted).extracting(String::length) + .isSorted(); } private int compareStrings(String s1, String s2) { return s1.length() - s2.length(); } + @SuppressWarnings("Convert2MethodRef") @Test // Use a lambda that calls 'compareStrings' directly public void stringLengthSort_methodCall() { - + List sorted = strings.stream() + .sorted((s1, s2) -> compareStrings(s1, s2)) + .toList(); + System.out.println(sorted); + assertThat(sorted).extracting(String::length) + .isSorted(); } @Test // Use a method ref to 'compareStrings' public void stringLengthSort_methodRef() { - + List sorted = strings.stream() + .sorted(this::compareStrings) + .toList(); + System.out.println(sorted); + assertThat(sorted).extracting(String::length) + .isSorted(); } @Test // Use Comparator.comparingInt public void stringLengthSort_comparingInt() { - + List sorted = strings.stream() + .sorted(Comparator.comparingInt(String::length) + .thenComparing(Comparator.naturalOrder())) + .toList(); + System.out.println(sorted); + assertThat(sorted).extracting(String::length) + .isSorted(); } @Test public void demoCollectors() { // Get only strings of even length // Add them to a LinkedList + Collection evens = strings.stream() + .filter(s -> s.length() % 2 == 0) + .collect(Collectors.toCollection(LinkedList::new)); + System.out.println(evens); + assertThat(evens).contains("is", "of", "this", "list"); // Add the strings to a map of string to length + Map map = strings.stream() + .distinct() + .collect(Collectors.toMap(Function.identity(), String::length)); + //.collect(Collectors.toMap(s -> s, String::length)); + System.out.println(map); // Filter out nulls, then print even-length strings + List stringsWithNulls = Arrays.asList("this", null, + "is", null, "a", null, "list", null, "of", null, "strings"); + List evenLengths = stringsWithNulls.stream() + // .filter(s -> s != null && s.length() % 2 == 0) // short-circuiting logical AND + .filter(Objects::nonNull) + .filter(s -> s.length() % 2 == 0) + .toList(); + System.out.println(evenLengths); // Function composition + Predicate nonNull = Objects::nonNull; + Predicate evenLength = s -> s.length() % 2 == 0; + + Logger logger = Logger.getLogger("demoCollectors"); + + Consumer print = System.out::println; + Consumer log = logger::info; // Combine the two predicates and use the result to print non-null, even-length strings + stringsWithNulls.stream() + .filter(nonNull.and(evenLength)) // function composition + .forEach(print.andThen(log)); // function composition - // f: A -> B, g: B -> C, (g.f)(x) = g(f(x)), A -> C + functionWithConsumer("Hello", String::toUpperCase, System.out::println); } - // generated by GitHub Copilot - private Function compose(Function f, Function g) { - return x -> g.apply(f.apply(x)); + // Combine a Function with a Consumer + public void functionWithConsumer(T value, Function function, Consumer consumer) { + consumer.accept(function.apply(value)); } - }