Change Log

v0.15.0

Released 2026-10-11

  • Breaking change: the BigDecimal-based moving and running gatherers (sum, product, simple average, exponential average, median, geometric mean, standard deviation) now return BigDecimalMovingStatGatherer or BigDecimalRunningStatGatherer. The public classes they used to return are removed: BigDecimalGatherer, BigDecimalExponentialMovingAverageGatherer, BigDecimalGeometricMeanGatherer, BigDecimalMedianGatherer, BigDecimalMovingGeometricMeanGatherer, BigDecimalMovingProductGatherer, BigDecimalMovingSumGatherer, BigDecimalProductGatherer, BigDecimalSimpleAverageGatherer, BigDecimalSimpleMovingAverageGatherer, BigDecimalStandardDeviationGatherer, and BigDecimalSumGatherer. Code that only calls the factory methods on Gatherers4j is unaffected, but code that names these types (for example in a variable declaration) must change.
  • Breaking change: remove the public SamplePercentageGatherers.poisson(). Use Gatherers4j.samplePercentage() instead.
  • Behavior change: the BigDecimal gatherers now round each input to the MathContext as it arrives, and sums, means, and standard deviations then accumulate exactly instead of rounding at every step. Results can differ from v0.14.0 in the final digits. Other numeric changes:
    • exponentialMovingAverageWithAlpha(), exponentialMovingAverageWithPeriod(), and their By variants now round at every step. Previously they never rounded, so results gained digits with every element and long streams became progressively slower.
    • Sample standard deviation (Dataset.Sample) now emits nothing for the first element, where runningSampleStandardDeviation() emitted 0.
  • treatNullAsOne() and withMathContext() are now available on all of the BigDecimal gatherers.
  • Rename simpleMovingAverage(), simpleMovingAverageBy(), simpleRunningAverage(), and simpleRunningAverageBy() to movingMean(), movingMeanBy(), runningMean(), and runningMeanBy().
  • Replace runningPopulationStandardDeviation(), runningPopulationStandardDeviationBy(), runningSampleStandardDeviation(), and runningSampleStandardDeviationBy() with runningStandardDeviation(Dataset) and runningStandardDeviationBy(Dataset, Function).
  • Implement movingStandardDeviation(Dataset, int) and movingStandardDeviationBy(Dataset, int, Function).
  • Fix bug in sampleFixedSize() where elements were not sampled with equal probability. The first sampleSize elements were chosen too rarely and later elements too often.
  • Implement sampleFixedSize(int, RandomGenerator) and samplePercentage(double, RandomGenerator) so callers can specify the source of randomness.
  • samplePercentage() now rejects NaN, which was previously accepted and silently emitted nothing.
  • exponentialMovingAverageWithAlpha() and exponentialMovingAverageWithAlphaBy() now reject NaN when called, instead of failing with NumberFormatException when the stream runs.
  • withMathContext() on the BigDecimal gatherers now rejects a MathContext with a precision of 0, such as MathContext.UNLIMITED, which made most statistics throw ArithmeticException when the stream ran.
  • Implement movingHarmonicMean(), movingHarmonicMeanBy(), runningHarmonicMean(), and runningHarmonicMeanBy().
  • Implement movingRootMeanSquare(), movingRootMeanSquareBy(), runningRootMeanSquare(), and runningRootMeanSquareBy().
  • Implement movingVariance(), movingVarianceBy(), runningVariance(), and runningVarianceBy()
  • Implement movingStatistics(), movingStatisticsBy(), runningStatistics(), and runningStatisticsBy(), which emit a StatisticalSummary record (count, sum, mean, min, max, and population and sample variance and standard deviation) for each element.
  • Implement movingPercentile(), movingPercentileBy(), runningPercentile(), and runningPercentileBy().
  • Implement movingWeightedMean() and movingWeightedMeanBy(), the weighted moving average. Weights run linearly from 1 (oldest) to the window size (newest) by default, or can be supplied as a List<BigDecimal> (or BigDecimal... for movingWeightedMean()) ordered oldest to newest.
  • Fix movingProduct(), movingProductBy(), movingGeometricMean(), and movingGeometricMeanBy() accumulating rounding error over long streams. Values leaving the window are no longer divided out of the product, and each step still takes constant time.
  • Fix movingMin(), movingMinBy(), movingMax(), and movingMaxBy() slowing down in proportion to the window size on steadily rising or falling input, and evicting the wrong values after about 2.1 billion elements.
  • Fix movingGeometricMean(), runningGeometricMean(), and their By variants throwing NumberFormatException or returning wrong results when the product of the values is outside the range of a double (above about 1E+308 or below about 1E-308).

v0.14.0

Released 2026-05-17

  • Implement movingGeometricMean(), movingGeometricMeanBy(), runningGeometricMean(), and runningGeometricMeanBy().
  • Implement filterNotNull(), which filters out null values from the input stream and is useful for lining up JSpecify annotations (from nullable to non-nullable).
  • Fix bug in movingProduct() and movingProductBy() where zero values were incorrectly handled. Addresses #184.
  • Change CrossGatherer, TypeFilteringGatherer, and FlattenSingleOrFail to use Greedy integrators.
  • Thank you to @Riggs333 for contributing code cleanups, making comparisons in FrequencyGatherer easier to understand!
  • Thank you to @Riggs333 for contributing changes to tests to use AssertJ’s type-specific exception assertions, which clarifies the intent of the code!

v0.13.0

Released 2026-01-04

  • Behavior change: All “moving” gatherers will now include all calculated values by default, even when the full lookback window has not been reached.
    • To turn this behavior off, use excludePartialValues().
    • Previously, partial results were suppressed and turned on via includePartialValues().
    • This affects movingMax(), movingMaxBy(), movingMin(), movingMinBy(), movingMedian(), movingMedianBy(), movingProduct(), movingProductBy(), movingSum(), movingSumBy(), simpleMovingAverage(), and simpleMovingAverageBy()
  • Implement uniquelyOccurringBy() to limit the stream to uniquely occurring elements as measured by the given function
  • Implement movingMedian() and movingMedianBy()
  • Implement runningMedian() and runningMedianBy()
  • Implement movingMax(), movingMaxBy(), movingMin(), and movingMinBy()
  • Implement runningMax(), runningMaxBy(), runningMin(), and runningMinBy()
  • Fixes to documentation

v0.12.0

Released 2025-09-27

  • Move Java version to 25 (was 24) Addresses #164
  • Support Java Modularization. Addresses #156, thanks @Goldmensch!
  • Support parallelization in UniquelyOccurringGatherer

v0.11.0

Released 2025-05-05

  • Fix and document behavior of window() when there are multiple partial groupings at the end. Addresses #135, thanks @paulk-asert!
  • Implement exponential moving averages with exponentialMovingAverageWithAlpha(), exponentialMovingAverageWithAlphaBy(),exponentialMovingAverageWithPeriod(), and exponentialMovingAverageWithPeriodBy().
  • Change index to be an int rather than a long in filterIndexed(), foldIndexed(), mapIndexed(), peekIndexed(), scanIndexed() and withIndex(). Addresses #140.
  • Optimize rotate(Left) to store a minimal set of elements instead of the entire stream. Addresses #141, thanks @paulk-asert!

v0.10.0

Released 2025-03-19

  • Upgrade the minimum Java version from 23 to 24
  • Implement mapIndexed() to perform a mapping operation given the element being mapped and its zero-based index
  • Implement peekIndexed() to peek at each element and its zero-based index
  • Implement sampleFixedSize() to randomly sample a fixed number of elements from a stream
  • Implement samplePercentage() to randomly sample a percentage of the stream elements
  • Rename IndexedValue to WithIndex, for consistency (matching WithCount and WithOriginal)

v0.9.0

Released 2025-02-23

  • Implement filterInstanceOf() to filter a stream by type more easily. Addresses #86, thanks @nipafx.
  • Implement groupOrdered(), and groupOrderedBy() to appropriately group elements in the input stream to lists in the output stream. Addresses #88, thanks @nipafx.
  • Implement ensureOrdered() and ensureOrderedBy() to ensure the given stream meets an ordering criteria, or fail exceptionally otherwise
  • Implement filterOrdered() and filterOrderedBy() to remove non-ordered elements from the input stream
  • Implement window() to provide more options to windowing functions, namely - ability to specify size, how many to skip each time, and whether to include partial windows
  • Implement repeat(n) and repeatInfinitely() to repeatedly emit the input stream to the output stream
  • Implement rotate(n) rotate the stream either left or right (consumes entire stream)
  • Renamed everyNth(n) to takeEveryNth(n) and added dropEveryNth(n) for completeness
  • Renamed filterWithIndex() to filterIndexed() to match other indexing Gatherers
  • Renamed cross() to crossWith() for consistency
  • Renamed interleave() to interleaveWith() for consistency
  • Renamed grouping() to group() and groupingBy() to groupBy() for consistency
  • Renamed last() to takeLast() to match dropLast()

v0.8.0

Released 2025-02-01

  • Add support for orElse() and orElseEmpty() on size-based gatherers to provide a non-exceptional output stream
  • Implement everyNth() to get every nth element from the stream
  • Implement uniquelyOccurring() to emit stream elements that occur a single time
  • Implement takeUntil() to take from a stream until a predicate is met, including the first element that matches the predicate
  • Implement foldIndexed() to perform a fold along with the index of each element
  • Implement scanIndexed() to perform a scan along with the index of each element
  • Implement intersperse() to put the given element between each element of the stream
  • Implement cross(iterable), cross(iterator), and cross(stream) to combine elements in the input stream with the given source of elements

v0.7.0

Released 2025-01-06

  • Use greedy integrators where possible (Addresses #57)
  • Add JSpecify annotations for static analysis
  • Implement orderByFrequencyAscending() and orderByFrequencyDescending()
  • Implement movingProduct() and movingProductBy()
  • Implement movingSum() and movingSumBy()
  • Remove maxBy(fn) and minBy(fn), can be done with JDK methods trivially
  • Rename exactSize() to sizeExactly()
  • Implement sizeLessThan(), sizeLessThanOrEqualTo(), sizeGreaterThan(), and sizeGreaterThanOrEqualTo()
  • API Style - Functions, when used as arguments, should come last for consistency and to play nice with Kotlin (Addresses #64)

v0.6.0

Released 2024-11-02

  • Implement dropLast(n)
  • Implement grouping() and groupingBy(fn)
  • Add support for zipWith(iterable) and zipWith(iterator)
    • With support for:
    • argumentWhenSourceLonger(fn)
    • sourceWhenArgumentLonger(fn)
    • nullArgumentWhenSourceLonger()
    • nullSourceWhenArgumentLonger()
  • Add support for interleave(iterable) and interleave(iterator)
    • With support for:
    • appendLonger()
    • appendArgumentIfLonger()
    • appendSourceIfLonger()

v0.5.0

Released 2024-10-13

  • Implement reverse() - Cause a stream to be emitted in reverse (stores entire stream in memory)
  • Implement maxBy(fn) and minBy(fn) - Finds the single maximum or minimum value in a stream as defined by the function given (stores entire stream in memory)
  • Implement exactSize(n) - Ensures a stream is precisely n elements long or throws an IllegalStateException (stores entire stream in memory)

v0.4.0

Released 2024-10-08

  • Implement shuffle() and shuffle(RandomGenerator)
  • Implement filterWithIndex()
  • Implement runningProduct() and runningProductBy()
  • Implement runningSum() and runningSumBy()
  • Remove concat() implementation (the JDK has this)
  • Remove withIndexStartingAt() from filterWithIndex(), not sure if this is a real use case.

v0.3.0

Released 2024-10-19

  • Upgrade the minimum Java version from 22 to 23

v0.2.0

Released 2024-08-22

  • Added throttle() over a time period
  • Added debounce() over a time period

v0.1.0

Released 2024-08-13

  • Added Standard Deviation (population and sample)
  • Refactored all BigDecimal-based Gatherers
  • Added concat

v0.0.1

Released 2024-07-29

  • Initial release