# Change Log

Site [llms.txt](/gatherers4j/llms.txt)

---

## v0.15.0
[Released 2026-10-11](https://github.com/tginsberg/gatherers4j/releases/tag/v0.15.0)
+ 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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.14.0)

+ 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](https://github.com/tginsberg/gatherers4j/issues/184).
+ Change `CrossGatherer`, `TypeFilteringGatherer`, and `FlattenSingleOrFail` to use Greedy integrators.
+ Thank you to [@Riggs333](https://github.com/Riggs333) for contributing code cleanups, making comparisons in `FrequencyGatherer` easier to understand!
+ Thank you to [@Riggs333](https://github.com/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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.13.0)

+ 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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.12.0)

+ Move Java version to 25 (was 24) Addresses [#164](https://github.com/tginsberg/gatherers4j/issues/164)
+ Support Java Modularization. Addresses [#156](https://github.com/tginsberg/gatherers4j/issues/156), thanks [@Goldmensch](https://github.com/Goldmensch)! 
+ Support parallelization in `UniquelyOccurringGatherer`

## v0.11.0
[Released 2025-05-05](https://github.com/tginsberg/gatherers4j/releases/tag/v0.11.0)

+ Fix and document behavior of `window()` when there are multiple partial groupings at the end. Addresses [#135](https://github.com/tginsberg/gatherers4j/issues/135), thanks [@paulk-asert](https://github.com/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](https://github.com/tginsberg/gatherers4j/issues/140). 
+ Optimize `rotate(Left)` to store a minimal set of elements instead of the entire stream. Addresses [#141](https://github.com/tginsberg/gatherers4j/issues/141), thanks [@paulk-asert](https://github.com/paulk-asert)! 

## v0.10.0
[Released 2025-03-19](https://github.com/tginsberg/gatherers4j/releases/tag/v0.10.0)

+ 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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.9.0)

+ Implement `filterInstanceOf()` to filter a stream by type more easily. Addresses [#86](https://github.com/tginsberg/gatherers4j/issues/86), thanks [@nipafx](https://github.com/nipafx).
+ Implement `groupOrdered()`, and `groupOrderedBy()` to appropriately group elements in the input stream to lists in the output stream. Addresses [#88](https://github.com/tginsberg/gatherers4j/issues/88), thanks [@nipafx](https://github.com/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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.8.0)

+ Add support for `orElse()` and `orElseEmpty()` on size-based gatherers to provide a non-exceptional output stream
+ Implement `everyNth()` to get every n<sup>th</sup> 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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.7.0)

+ Use greedy integrators where possible (Addresses [#57](https://github.com/tginsberg/gatherers4j/issues/57))
+ Add [JSpecify](https://jspecify.dev/) 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](https://github.com/tginsberg/gatherers4j/issues/64))

## v0.6.0
[Released 2024-11-02](https://github.com/tginsberg/gatherers4j/releases/tag/v0.6.0)

+ 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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.5.0)
+ 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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.4.0)
+ 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](https://github.com/tginsberg/gatherers4j/releases/tag/v0.3.0)
+ Upgrade the minimum Java version from 22 to 23

## v0.2.0
[Released 2024-08-22](https://github.com/tginsberg/gatherers4j/releases/tag/v0.2.0)
+ Added `throttle()` over a time period
+ Added `debounce()` over a time period

## v0.1.0
[Released 2024-08-13](https://github.com/tginsberg/gatherers4j/releases/tag/v0.1.0)
+ Added Standard Deviation (population and sample)
+ Refactored all BigDecimal-based Gatherers
+ Added concat

## v0.0.1
[Released 2024-07-29](https://github.com/tginsberg/gatherers4j/releases/tag/v0.0.1)
+ Initial release
