| 1 | package com.pivovarit.gatherers; | |
| 2 | ||
| 3 | import java.util.Iterator; | |
| 4 | import java.util.List; | |
| 5 | import java.util.Map; | |
| 6 | import java.util.Objects; | |
| 7 | import java.util.function.BiFunction; | |
| 8 | import java.util.function.BiPredicate; | |
| 9 | import java.util.function.Function; | |
| 10 | import java.util.stream.Collector; | |
| 11 | import java.util.stream.Collectors; | |
| 12 | import java.util.stream.Gatherer; | |
| 13 | import java.util.stream.Stream; | |
| 14 | ||
| 15 | /// Contains various [java.util.stream.Gatherer] implementations expanding [java.util.stream.Stream] API functionality | |
| 16 | public final class MoreGatherers { | |
| 17 | ||
| 18 | private MoreGatherers() { | |
| 19 | } | |
| 20 | ||
| 21 | /** | |
| 22 | * Creates a {@link Gatherer} that gathers the last {@code n} elements. | |
| 23 | * | |
| 24 | * @param <T> the type of the input elements | |
| 25 | * @param n the number of last elements to gather | |
| 26 | * | |
| 27 | * @return a {@link Gatherer} that collects the last {@code n} elements | |
| 28 | */ | |
| 29 | public static <T> Gatherer<T, ?, T> last(int n) { | |
| 30 |
1
1. last : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::last → KILLED |
return LastGatherer.size(n); |
| 31 | } | |
| 32 | ||
| 33 | /** | |
| 34 | * Creates a {@link Gatherer} that gathers every {@code n}-th element. | |
| 35 | * | |
| 36 | * @param <T> the type of the input elements | |
| 37 | * @param n the interval at which elements are gathered | |
| 38 | * | |
| 39 | * @return a {@link Gatherer} that samples elements every {@code n}-th element | |
| 40 | */ | |
| 41 | public static <T> Gatherer<T, ?, T> sampling(int n) { | |
| 42 |
1
1. sampling : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::sampling → KILLED |
return new SamplingGatherer<>(n); |
| 43 | } | |
| 44 | ||
| 45 | /** | |
| 46 | * Creates a {@link Gatherer} that filters elements to ensure that only distinct elements | |
| 47 | * remain, based on a key extracted by the given {@code keyExtractor}, keeping the last | |
| 48 | * occurrence of each distinct key. | |
| 49 | * | |
| 50 | * @param <T> the type of the input elements | |
| 51 | * @param <U> the type of the key extracted from the input elements | |
| 52 | * @param keyExtractor the function used to extract the key for distinguishing elements | |
| 53 | * | |
| 54 | * @return a {@link Gatherer} that collects distinct elements by key, keeping the last occurrence | |
| 55 | */ | |
| 56 | public static <T, U> Gatherer<T, ?, T> distinctByKeepLast(Function<? super T, ? extends U> keyExtractor) { | |
| 57 |
1
1. distinctByKeepLast : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::distinctByKeepLast → KILLED |
return new DistinctByKeepLastGatherer<>(keyExtractor); |
| 58 | } | |
| 59 | ||
| 60 | /** | |
| 61 | * Creates a {@link Gatherer} that filters elements to ensure that only distinct elements | |
| 62 | * remain, based on a key extracted by the given {@code keyExtractor}, keeping the first | |
| 63 | * occurrence of each distinct key. | |
| 64 | * | |
| 65 | * @param <T> the type of the input elements | |
| 66 | * @param <U> the type of the key extracted from the input elements | |
| 67 | * @param keyExtractor the function used to extract the key for distinguishing elements | |
| 68 | * | |
| 69 | * @return a {@link Gatherer} that collects distinct elements by key, keeping the first occurrence | |
| 70 | */ | |
| 71 | public static <T, U> Gatherer<T, ?, T> distinctBy(Function<? super T, ? extends U> keyExtractor) { | |
| 72 |
1
1. distinctBy : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::distinctBy → KILLED |
return new DistinctByGatherer<>(keyExtractor); |
| 73 | } | |
| 74 | ||
| 75 | /** | |
| 76 | * Creates a {@link Gatherer} that gathers distinct consecutive elements. | |
| 77 | * Elements are considered distinct if they are different from the previously gathered element. | |
| 78 | * | |
| 79 | * @param <T> the type of the input elements | |
| 80 | * | |
| 81 | * @return a {@link Gatherer} that collects distinct consecutive elements | |
| 82 | */ | |
| 83 | public static <T> Gatherer<T, ?, T> distinctUntilChanged() { | |
| 84 |
1
1. distinctUntilChanged : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::distinctUntilChanged → KILLED |
return distinctUntilChanged(Function.identity()); |
| 85 | } | |
| 86 | ||
| 87 | /** | |
| 88 | * Creates a {@link Gatherer} that gathers distinct consecutive elements | |
| 89 | * based on a key extracted by the given {@code keyExtractor}. | |
| 90 | * Elements are considered distinct if the extracted key is different from the previous key. | |
| 91 | * | |
| 92 | * @param <T> the type of the input elements | |
| 93 | * @param <U> the type of the key extracted from the input elements | |
| 94 | * @param keyExtractor the function used to extract the key for distinguishing elements | |
| 95 | * | |
| 96 | * @return a {@link Gatherer} that collects distinct consecutive elements by key | |
| 97 | */ | |
| 98 | public static <T, U> Gatherer<T, ?, T> distinctUntilChanged(Function<? super T, ? extends U> keyExtractor) { | |
| 99 | Objects.requireNonNull(keyExtractor, "keyExtractor can't be null"); | |
| 100 |
1
1. distinctUntilChanged : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::distinctUntilChanged → KILLED |
return new DistinctUntilChangedGatherer<>(keyExtractor); |
| 101 | } | |
| 102 | ||
| 103 | /** | |
| 104 | * Creates a {@link Gatherer} that zips elements of type {@code T1} with elements from | |
| 105 | * another {@link Stream} of type {@code T2}. The resulting pair is returned as a {@link Map.Entry}. | |
| 106 | * | |
| 107 | * @param <T1> the type of the first stream elements | |
| 108 | * @param <T2> the type of the second stream elements | |
| 109 | * @param other the other stream to zip with | |
| 110 | * | |
| 111 | * @return a {@link Gatherer} that pairs elements from the two streams | |
| 112 | */ | |
| 113 | public static <T1, T2> Gatherer<T1, ?, Map.Entry<T1, T2>> zip(Stream<T2> other) { | |
| 114 | Objects.requireNonNull(other, "other can't be null"); | |
| 115 |
1
1. zip : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zip → KILLED |
return zip(other.iterator()); |
| 116 | } | |
| 117 | ||
| 118 | /** | |
| 119 | * Creates a {@link Gatherer} that zips elements of type {@code T1} with elements from | |
| 120 | * another {@link Stream} of type {@code T2}, and combines them using the provided {@code mapper}. | |
| 121 | * | |
| 122 | * @param <T1> the type of the first stream elements | |
| 123 | * @param <T2> the type of the second stream elements | |
| 124 | * @param <R> the type of the result produced by the {@code mapper} | |
| 125 | * @param other the other stream to zip with | |
| 126 | * @param mapper the function that combines elements from both streams | |
| 127 | * | |
| 128 | * @return a {@link Gatherer} that pairs elements from the two streams using the {@code mapper} | |
| 129 | */ | |
| 130 | public static <T1, T2, R> Gatherer<T1, ?, R> zip(Stream<T2> other, BiFunction<? super T1, ? super T2, ? extends R> mapper) { | |
| 131 | Objects.requireNonNull(other, "other can't be null"); | |
| 132 |
1
1. zip : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zip → KILLED |
return zip(other.iterator(), mapper); |
| 133 | } | |
| 134 | ||
| 135 | /** | |
| 136 | * Creates a {@link Gatherer} that zips elements of type {@code T1} with elements from | |
| 137 | * another {@link Iterable} of type {@code T2}. The resulting pair is returned as a {@link Map.Entry}. | |
| 138 | * | |
| 139 | * @param <T1> the type of the first iterable elements | |
| 140 | * @param <T2> the type of the second iterable elements | |
| 141 | * @param other the other iterable to zip with | |
| 142 | * | |
| 143 | * @return a {@link Gatherer} that pairs elements from the two iterables | |
| 144 | */ | |
| 145 | public static <T1, T2> Gatherer<T1, ?, Map.Entry<T1, T2>> zipWithIterable(Iterable<T2> other) { | |
| 146 | Objects.requireNonNull(other, "other can't be null"); | |
| 147 |
1
1. zipWithIterable : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zipWithIterable → KILLED |
return zip(other.iterator()); |
| 148 | } | |
| 149 | ||
| 150 | /** | |
| 151 | * Creates a {@link Gatherer} that zips elements of type {@code T1} with elements from | |
| 152 | * another {@link Iterable} of type {@code T2}, and combines them using the provided {@code mapper}. | |
| 153 | * | |
| 154 | * @param <T1> the type of the first iterable elements | |
| 155 | * @param <T2> the type of the second iterable elements | |
| 156 | * @param <R> the type of the result produced by the {@code mapper} | |
| 157 | * @param other the other iterable to zip with | |
| 158 | * @param mapper the function that combines elements from both iterables | |
| 159 | * | |
| 160 | * @return a {@link Gatherer} that pairs elements from the two iterables using the {@code mapper} | |
| 161 | */ | |
| 162 | public static <T1, T2, R> Gatherer<T1, ?, R> zipWithIterable(Iterable<T2> other, BiFunction<? super T1, ? super T2, ? extends R> mapper) { | |
| 163 | Objects.requireNonNull(other, "other can't be null"); | |
| 164 | Objects.requireNonNull(mapper, "mapper can't be null"); | |
| 165 |
1
1. zipWithIterable : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zipWithIterable → KILLED |
return zip(other.iterator(), mapper); |
| 166 | } | |
| 167 | ||
| 168 | /** | |
| 169 | * Creates a {@link Gatherer} that zips elements of type {@code T1} with elements from | |
| 170 | * another {@link Iterator} of type {@code T2}. The resulting pair is returned as a {@link Map.Entry}. | |
| 171 | * | |
| 172 | * @param <T1> the type of the first iterator elements | |
| 173 | * @param <T2> the type of the second iterator elements | |
| 174 | * @param iterator the iterator to zip with | |
| 175 | * | |
| 176 | * @return a {@link Gatherer} that pairs elements from the two iterators | |
| 177 | */ | |
| 178 | public static <T1, T2> Gatherer<T1, ?, Map.Entry<T1, T2>> zip(Iterator<T2> iterator) { | |
| 179 |
1
1. zip : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zip → KILLED |
return zip(iterator, Map::entry); |
| 180 | } | |
| 181 | ||
| 182 | /** | |
| 183 | * Creates a {@link Gatherer} that zips elements of type {@code T1} with elements from | |
| 184 | * another {@link Iterator} of type {@code T2}, and combines them using the provided {@code mapper}. | |
| 185 | * | |
| 186 | * @param <T1> the type of the first iterator elements | |
| 187 | * @param <T2> the type of the second iterator elements | |
| 188 | * @param <R> the type of the result produced by the {@code mapper} | |
| 189 | * @param iterator the iterator to zip with | |
| 190 | * @param mapper the function that combines elements from both iterators | |
| 191 | * | |
| 192 | * @return a {@link Gatherer} that pairs elements from the two iterators using the {@code mapper} | |
| 193 | */ | |
| 194 | public static <T1, T2, R> Gatherer<T1, ?, R> zip(Iterator<T2> iterator, BiFunction<? super T1, ? super T2, ? extends R> mapper) { | |
| 195 |
1
1. zip : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zip → KILLED |
return new ZipIteratorGatherer<>(iterator, mapper); |
| 196 | } | |
| 197 | ||
| 198 | /** | |
| 199 | * Creates a {@link Gatherer} that zips elements with their corresponding index, | |
| 200 | * using the given {@code mapper} to produce the final result. | |
| 201 | * | |
| 202 | * @param <T> the type of the input elements | |
| 203 | * @param <R> the type of the result produced by the {@code mapper} | |
| 204 | * @param mapper the function that combines an index and an element to produce the result | |
| 205 | * | |
| 206 | * @return a {@link Gatherer} that pairs elements with their corresponding index using the {@code mapper} | |
| 207 | */ | |
| 208 | public static <T, R> Gatherer<T, ?, R> zipWithIndex(BiFunction<Long, ? super T, ? extends R> mapper) { | |
| 209 |
1
1. zipWithIndex : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zipWithIndex → KILLED |
return new ZipWithIndexMappingGatherer<>(mapper); |
| 210 | } | |
| 211 | ||
| 212 | /** | |
| 213 | * Creates a {@link Gatherer} that zips elements with their corresponding index, | |
| 214 | * producing a {@link Map.Entry} where the key is the index and the value is the element. | |
| 215 | * | |
| 216 | * @param <T> the type of the input elements | |
| 217 | * | |
| 218 | * @return a {@link Gatherer} that pairs elements with their corresponding index | |
| 219 | */ | |
| 220 | public static <T> Gatherer<T, ?, Map.Entry<T, Long>> zipWithIndex() { | |
| 221 |
1
1. zipWithIndex : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zipWithIndex → KILLED |
return new ZipWithIndexGatherer<>(); |
| 222 | } | |
| 223 | ||
| 224 | /** | |
| 225 | * Creates a {@link Gatherer} that collects elements into sliding windows of a specified size. | |
| 226 | * Each window captures a subset of elements from the input, and windows slide by a specified step. | |
| 227 | * <p> | |
| 228 | * This {@link Gatherer} extends {@link java.util.stream.Gatherers#windowSliding(int)} by allowing to customize the step | |
| 229 | * | |
| 230 | * <p>For example, if the window size is 3 and the step is 1, the gatherer will collect | |
| 231 | * windows of size 3, sliding by 1 element at a time. This means each subsequent window overlaps | |
| 232 | * with the previous one by two elements.</p> | |
| 233 | * | |
| 234 | * <p>Common use cases include moving averages, trend analysis, and any scenario requiring | |
| 235 | * overlapping or rolling window operations on a list of elements.</p> | |
| 236 | * | |
| 237 | * @param <T> the type of elements in the input and output list | |
| 238 | * @param windowSize the size of each window (must be a positive integer) | |
| 239 | * @param step the number of elements to slide the window by (must be a positive integer) | |
| 240 | * | |
| 241 | * @return a {@link Gatherer} that collects elements into sliding windows | |
| 242 | * | |
| 243 | * @throws IllegalArgumentException if {@code windowSize} is less than one or {@code step} is less than zero, or greater than {@code windowSize} | |
| 244 | */ | |
| 245 | public static <T> Gatherer<T, ?, List<T>> windowSliding(int windowSize, int step) { | |
| 246 |
1
1. windowSliding : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::windowSliding → KILLED |
return new WindowSlidingGatherer<>(windowSize, step); |
| 247 | } | |
| 248 | ||
| 249 | /** | |
| 250 | * Creates a {@link Gatherer} that filters elements based on their index and value using a given {@link BiPredicate}. | |
| 251 | * The provided {@code BiPredicate} is applied to each element of the source, along with its corresponding index | |
| 252 | * (starting from 0). Only the elements that satisfy the predicate (i.e., for which the predicate returns {@code true}) | |
| 253 | * are retained. | |
| 254 | * <p> | |
| 255 | * The same result can be achieved by using {@code zipWithIndex()}, {@code filter()}, and {@code map()}. | |
| 256 | * However, this method is significantly faster because it avoids the intermediate steps and directly filters | |
| 257 | * elements based on their index. | |
| 258 | * | |
| 259 | * @param <T> the type of elements to be filtered | |
| 260 | * @param predicate a {@link BiPredicate} that takes the index and element as input, and returns {@code true} to retain | |
| 261 | * the element, or {@code false} to exclude it | |
| 262 | * | |
| 263 | * @return a {@link Gatherer} that applies the given filter based on element index and value | |
| 264 | */ | |
| 265 | public static <T> Gatherer<T, ?, T> filteringByIndex(BiPredicate<Long, ? super T> predicate) { | |
| 266 |
1
1. filteringByIndex : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::filteringByIndex → KILLED |
return new FilterByIndexGatherer<>(predicate); |
| 267 | } | |
| 268 | ||
| 269 | /** | |
| 270 | * Creates a {@link Gatherer} that groups elements based on a key extracted by the given {@code classifier}. | |
| 271 | * | |
| 272 | * @param classifier the function used to extract the key for grouping elements | |
| 273 | * @param collector the {@link Collector} used to accumulate the elements of each group | |
| 274 | * @param <T> the type of the input elements | |
| 275 | * @param <K> the type of the key extracted from the input elements | |
| 276 | * @param <R> the type of the result of the collector | |
| 277 | * | |
| 278 | * @return a {@link Gatherer} that groups elements based on the extracted key | |
| 279 | */ | |
| 280 | public static <T, K, R> Gatherer<T, ?, Map.Entry<K, R>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, ?, ? extends R> collector) { | |
| 281 |
1
1. groupingBy : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::groupingBy → KILLED |
return new GroupingByGatherer<>(classifier, collector); |
| 282 | } | |
| 283 | ||
| 284 | /** | |
| 285 | * Creates a {@link Gatherer} that groups elements based on a key extracted by the given {@code classifier}. | |
| 286 | * | |
| 287 | * @param classifier the function used to extract the key for grouping elements | |
| 288 | * @param <T> the type of the input elements | |
| 289 | * @param <K> the type of the key extracted from the input elements | |
| 290 | * | |
| 291 | * @return a {@link Gatherer} that groups elements based on the extracted key | |
| 292 | */ | |
| 293 | public static <T, K> Gatherer<T, ?, Map.Entry<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier) { | |
| 294 |
1
1. groupingBy : replaced return value with null for com/pivovarit/gatherers/MoreGatherers::groupingBy → KILLED |
return groupingBy(classifier, Collectors.toList()); |
| 295 | } | |
| 296 | } | |
Mutations | ||
| 30 |
1.1 |
|
| 42 |
1.1 |
|
| 57 |
1.1 |
|
| 72 |
1.1 |
|
| 84 |
1.1 |
|
| 100 |
1.1 |
|
| 115 |
1.1 |
|
| 132 |
1.1 |
|
| 147 |
1.1 |
|
| 165 |
1.1 |
|
| 179 |
1.1 |
|
| 195 |
1.1 |
|
| 209 |
1.1 |
|
| 221 |
1.1 |
|
| 246 |
1.1 |
|
| 266 |
1.1 |
|
| 281 |
1.1 |
|
| 294 |
1.1 |