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

Mutations

28

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

40

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

55

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

70

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

82

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

98

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

113

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

130

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

145

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

163

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

177

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

193

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

207

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

219

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

244

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

264

1.1
Location : byIndex
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::byIndex → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.1