MoreGatherers.java

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
Location : last
Killed by : com.pivovarit.gatherers.blackbox.LastTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.LastTest]/[method:shouldLastEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::last → KILLED

42

1.1
Location : sampling
Killed by : com.pivovarit.gatherers.blackbox.SamplingTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.SamplingTest]/[method:shouldSampleEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::sampling → KILLED

57

1.1
Location : distinctByKeepLast
Killed by : com.pivovarit.gatherers.blackbox.DistinctByKeepLastTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.DistinctByKeepLastTest]/[method:shouldDistinctBy()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::distinctByKeepLast → KILLED

72

1.1
Location : distinctBy
Killed by : com.pivovarit.gatherers.blackbox.DistinctByTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.DistinctByTest]/[method:shouldDistinctByEmptyStream()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::distinctBy → KILLED

84

1.1
Location : distinctUntilChanged
Killed by : com.pivovarit.gatherers.blackbox.DistinctUntilChangedTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.DistinctUntilChangedTest]/[method:shouldDistinctUntilChangedEmptyStream()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::distinctUntilChanged → KILLED

100

1.1
Location : distinctUntilChanged
Killed by : com.pivovarit.gatherers.blackbox.DistinctUntilChangedMapperTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.DistinctUntilChangedMapperTest]/[method:shouldDistinctUntilChangedEmptyStream()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::distinctUntilChanged → KILLED

115

1.1
Location : zip
Killed by : com.pivovarit.gatherers.blackbox.ZipStreamTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ZipStreamTest]/[method:shouldZipEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zip → KILLED

132

1.1
Location : zip
Killed by : com.pivovarit.gatherers.blackbox.ZipStreamMapperTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ZipStreamMapperTest]/[method:shouldZipEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zip → KILLED

147

1.1
Location : zipWithIterable
Killed by : com.pivovarit.gatherers.blackbox.ZipWithIterableTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ZipWithIterableTest]/[method:shouldZipEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zipWithIterable → KILLED

165

1.1
Location : zipWithIterable
Killed by : com.pivovarit.gatherers.blackbox.ZipWithIterableMapperTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ZipWithIterableMapperTest]/[method:shouldZipEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zipWithIterable → KILLED

179

1.1
Location : zip
Killed by : com.pivovarit.gatherers.blackbox.ZipIteratorTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ZipIteratorTest]/[method:shouldZipWithEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zip → KILLED

195

1.1
Location : zip
Killed by : com.pivovarit.gatherers.blackbox.ZipIteratorMapperTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ZipIteratorMapperTest]/[method:shouldZipEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zip → KILLED

209

1.1
Location : zipWithIndex
Killed by : com.pivovarit.gatherers.blackbox.ZipWithIndexMapperTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ZipWithIndexMapperTest]/[method:shouldZipEmptyStream()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zipWithIndex → KILLED

221

1.1
Location : zipWithIndex
Killed by : com.pivovarit.gatherers.blackbox.ZipWithIndexTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ZipWithIndexTest]/[method:shouldZipEmptyStream()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::zipWithIndex → KILLED

246

1.1
Location : windowSliding
Killed by : com.pivovarit.gatherers.blackbox.WindowSlidingTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.WindowSlidingTest]/[method:shouldWindowSlidingEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::windowSliding → KILLED

266

1.1
Location : filteringByIndex
Killed by : com.pivovarit.gatherers.blackbox.ByIndexTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.ByIndexTest]/[method:shouldFilterByIndexEmptyStream()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::filteringByIndex → KILLED

281

1.1
Location : groupingBy
Killed by : com.pivovarit.gatherers.blackbox.GroupingByGathererTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.GroupingByGathererTest]/[method:shouldGroupEmptyWithCustomCollector()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::groupingBy → KILLED

294

1.1
Location : groupingBy
Killed by : com.pivovarit.gatherers.blackbox.GroupingByGathererTest.[engine:junit-jupiter]/[class:com.pivovarit.gatherers.blackbox.GroupingByGathererTest]/[method:shouldGroupEmpty()]
replaced return value with null for com/pivovarit/gatherers/MoreGatherers::groupingBy → KILLED

Active mutators

Tests examined


Report generated by PIT 1.18.0