From d441b3ce969f3365a834e7d3c4c16bb08ba9522b Mon Sep 17 00:00:00 2001 From: Andreas Hufler Date: Tue, 30 Sep 2025 08:24:19 +0200 Subject: [PATCH 1/2] add filter util --- .../springboot/toolbox/util/FilterUtil.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/main/java/it/aboutbits/springboot/toolbox/util/FilterUtil.java diff --git a/src/main/java/it/aboutbits/springboot/toolbox/util/FilterUtil.java b/src/main/java/it/aboutbits/springboot/toolbox/util/FilterUtil.java new file mode 100644 index 0000000..b61f5c3 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/toolbox/util/FilterUtil.java @@ -0,0 +1,72 @@ +package it.aboutbits.springboot.toolbox.util; + +import lombok.NonNull; +import org.springframework.data.util.Streamable; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * This is a collection of tools to simply filter items to a new collection or stream. + *

+ * The returned collections are unmodifiable. + */ +public final class FilterUtil { + private FilterUtil() { + } + + public static Set filterToSet(@NonNull Collection items, @NonNull Predicate filter) { + return items.stream() + .filter(filter) + .collect(Collectors.toUnmodifiableSet()); + } + + public static Set filterToSet(@NonNull Streamable items, @NonNull Predicate filter) { + return items.stream() + .filter(filter) + .collect(Collectors.toUnmodifiableSet()); + } + + public static Set filterToSet(@NonNull Stream items, @NonNull Predicate filter) { + return items + .filter(filter) + .collect(Collectors.toUnmodifiableSet()); + } + + public static List filterToList(@NonNull Collection items, @NonNull Predicate filter) { + return items.stream() + .filter(filter) + .toList(); + } + + public static List filterToList(@NonNull Streamable items, @NonNull Predicate filter) { + return items.stream() + .filter(filter) + .toList(); + } + + public static List filterToList(@NonNull Stream items, @NonNull Predicate filter) { + return items + .filter(filter) + .toList(); + } + + public static Stream filterToStream(@NonNull Collection items, @NonNull Predicate filter) { + return items.stream() + .filter(filter); + } + + public static Stream filterToStream(@NonNull Streamable items, @NonNull Predicate filter) { + return items.stream() + .filter(filter); + } + + public static Stream filterToStream(@NonNull Stream items, @NonNull Predicate filter) { + return items + .filter(filter); + } +} From b7d0c5e2ed31fbc201e674a6074c33314c7d7b03 Mon Sep 17 00:00:00 2001 From: Andreas Hufler Date: Tue, 30 Sep 2025 08:48:36 +0200 Subject: [PATCH 2/2] add tests --- .../toolbox/util/FilterUtilTest.java | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 src/test/java/it/aboutbits/springboot/toolbox/util/FilterUtilTest.java diff --git a/src/test/java/it/aboutbits/springboot/toolbox/util/FilterUtilTest.java b/src/test/java/it/aboutbits/springboot/toolbox/util/FilterUtilTest.java new file mode 100644 index 0000000..505955e --- /dev/null +++ b/src/test/java/it/aboutbits/springboot/toolbox/util/FilterUtilTest.java @@ -0,0 +1,265 @@ +package it.aboutbits.springboot.toolbox.util; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.data.util.Streamable; + +import java.util.Arrays; +import java.util.Collections; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class FilterUtilTest { + @Nested + class FilterToSet { + @Test + @DisplayName("Should filter Collection to Set using predicate") + void shouldFilterCollectionToSetUsingPredicate() { + // given + var numbers = Arrays.asList(1, 2, 3, 4, 5); + + // when + var result = FilterUtil.filterToSet(numbers, n -> n > 2); + + // then + assertThat(result).containsExactlyInAnyOrder(3, 4, 5); + } + + @Test + @DisplayName("Should handle empty Collection when filtering to Set") + void shouldHandleEmptyCollectionWhenFilteringToSet() { + // given + var emptyList = Collections.emptyList(); + + // when + var result = FilterUtil.filterToSet(emptyList, n -> n > 2); + + // then + assertTrue(result.isEmpty()); + } + + @Test + @DisplayName("Should remove duplicates when filtering Collection to Set") + void shouldRemoveDuplicatesWhenFilteringCollectionToSet() { + // given + var numbersWithDuplicates = Arrays.asList(1, 2, 2, 3, 3, 3); + + // when + var result = FilterUtil.filterToSet(numbersWithDuplicates, n -> n >= 2); + + // then + assertThat(result).containsExactlyInAnyOrder(2, 3); + assertThat(result).hasSize(2); + } + + @Test + @DisplayName("Should filter Streamable to Set using predicate") + void shouldFilterStreamableToSetUsingPredicate() { + // given + var numbers = Streamable.of(1, 2, 3, 4, 5); + + // when + var result = FilterUtil.filterToSet(numbers, n -> n % 2 == 0); + + // then + assertThat(result).containsExactlyInAnyOrder(2, 4); + } + + @Test + @DisplayName("Should handle empty Streamable when filtering to Set") + void shouldHandleEmptyStreamableWhenFilteringToSet() { + // given + var emptyStreamable = Streamable.empty(); + + // when + var result = FilterUtil.filterToSet(emptyStreamable, n -> n > 2); + + // then + assertTrue(result.isEmpty()); + } + + @Test + @DisplayName("Should remove duplicates when filtering Stream to Set") + void shouldRemoveDuplicatesWhenFilteringStreamToSet() { + // given + var numbersWithDuplicates = Stream.of(1, 2, 2, 3, 3, 3); + + // when + var result = FilterUtil.filterToSet(numbersWithDuplicates, n -> n >= 2); + + // then + assertThat(result).containsExactlyInAnyOrder(2, 3); + assertThat(result).hasSize(2); + } + } + + @Nested + class FilterToList { + @Test + @DisplayName("Should filter Collection to List using predicate") + void shouldFilterCollectionToListUsingPredicate() { + // given + var numbers = Arrays.asList(1, 2, 3, 4, 5); + + // when + var result = FilterUtil.filterToList(numbers, n -> n % 2 == 1); + + // then + assertThat(result).containsExactly(1, 3, 5); + } + + @Test + @DisplayName("Should handle empty Collection when filtering to List") + void shouldHandleEmptyCollectionWhenFilteringToList() { + // given + var emptyList = Collections.emptyList(); + + // when + var result = FilterUtil.filterToList(emptyList, n -> n > 2); + + // then + assertTrue(result.isEmpty()); + } + + @Test + @DisplayName("Should preserve duplicates when filtering Collection to List") + void shouldPreserveDuplicatesWhenFilteringCollectionToList() { + // given + var numbersWithDuplicates = Arrays.asList(1, 2, 2, 3, 3, 3); + + // when + var result = FilterUtil.filterToList(numbersWithDuplicates, n -> n >= 2); + + // then + assertThat(result).containsExactly(2, 2, 3, 3, 3); + assertThat(result).hasSize(5); + } + + @Test + @DisplayName("Should filter Streamable to List using predicate") + void shouldFilterStreamableToListUsingPredicate() { + // given + var numbers = Streamable.of(1, 2, 3, 4, 5); + + // when + var result = FilterUtil.filterToList(numbers, n -> n < 4); + + // then + assertThat(result).containsExactly(1, 2, 3); + } + + @Test + @DisplayName("Should handle empty Streamable when filtering to List") + void shouldHandleEmptyStreamableWhenFilteringToList() { + // given + var emptyStreamable = Streamable.empty(); + + // when + var result = FilterUtil.filterToList(emptyStreamable, n -> n > 2); + + // then + assertTrue(result.isEmpty()); + } + + @Test + @DisplayName("Should preserve duplicates when filtering Stream to List") + void shouldPreserveDuplicatesWhenFilteringStreamToList() { + // given + var numbersWithDuplicates = Stream.of(1, 2, 2, 3, 3, 3); + + // when + var result = FilterUtil.filterToList(numbersWithDuplicates, n -> n >= 2); + + // then + assertThat(result).containsExactly(2, 2, 3, 3, 3); + assertThat(result).hasSize(5); + } + } + + @Nested + class FilterToStream { + @Test + @DisplayName("Should filter Collection to Stream using predicate") + void shouldFilterCollectionToStreamUsingPredicate() { + // given + var numbers = Arrays.asList(1, 2, 3, 4, 5); + + // when + var resultStream = FilterUtil.filterToStream(numbers, n -> n >= 4); + + // then + var result = resultStream.toList(); + assertThat(result).containsExactly(4, 5); + } + + @Test + @DisplayName("Should handle empty Collection when filtering to Stream") + void shouldHandleEmptyCollectionWhenFilteringToStream() { + // given + var emptyList = Collections.emptyList(); + + // when + var resultStream = FilterUtil.filterToStream(emptyList, n -> n > 2); + + // then + assertTrue(resultStream.toList().isEmpty()); + } + + @Test + @DisplayName("Should filter Streamable to Stream using predicate") + void shouldFilterStreamableToStreamUsingPredicate() { + // given + var numbers = Streamable.of(1, 2, 3, 4, 5); + + // when + var resultStream = FilterUtil.filterToStream(numbers, n -> n <= 2); + + // then + var result = resultStream.toList(); + assertThat(result).containsExactly(1, 2); + } + + @Test + @DisplayName("Should handle empty Streamable when filtering to Stream") + void shouldHandleEmptyStreamableWhenFilteringToStream() { + // given + var emptyStreamable = Streamable.empty(); + + // when + var resultStream = FilterUtil.filterToStream(emptyStreamable, n -> n > 2); + + // then + assertTrue(resultStream.toList().isEmpty()); + } + + @Test + @DisplayName("Should filter Stream to Stream using predicate") + void shouldFilterStreamToStreamUsingPredicate() { + // given + var numbers = Stream.of(1, 2, 3, 4, 5); + + // when + var resultStream = FilterUtil.filterToStream(numbers, n -> n % 2 == 0); + + // then + var result = resultStream.toList(); + assertThat(result).containsExactly(2, 4); + } + + @Test + @DisplayName("Should handle empty Stream when filtering to Stream") + void shouldHandleEmptyStreamWhenFilteringToStream() { + // given + var emptyStream = Stream.empty(); + + // when + var resultStream = FilterUtil.filterToStream(emptyStream, n -> n > 2); + + // then + assertTrue(resultStream.toList().isEmpty()); + } + } +}