counter
Counter: iterators whose values only increase or only decrease
Interfaces for counters: Iterators whose values only increase or only decrease, over any Comparable type, with no dependencies beyond the JDK.
Rationale
Why. Ticket numbers, attempt counts, version stamps and clocks all issue values in one direction. Code that consumes them needs that direction, not a particular implementation.
Problem. A plain Iterator<T> or Supplier<T> says nothing about order, so a caller cannot tell from the type whether the next value can repeat or go back.
Solution. The direction is a type. Accept an Increasing.Strict<T> where values must never repeat, or an Increasing<T> where they may repeat but never fall, and the caller may supply any implementation.
Key Concepts
Counter
Role. An Iterator<T> over Comparable values. hasNext() is true by default, for a counter with no last value; a counter with one overrides it. It is sealed: every counter is Increasing or Decreasing.
Increasing
Role. Each next() is greater than or equal to the one before. Increasing.Strict requires greater, so no value repeats.
Decreasing
Role. Each next() is less than or equal to the one before. Decreasing.Strict requires less, so no value repeats.
How It Works
Guarantees. The interfaces declare an order but cannot enforce it; each implementation must keep it. next() is the one abstract method, so a lambda or method reference can implement Increasing, Decreasing or their Strict subtypes.
Thread safety. Thread safety is up to each implementation.
Lane
Purpose. Typing a source of values that only increase or only decrease.
When to avoid. Values that may move in either direction: use Iterator or Stream.
Usage
A strictly increasing counter from a method reference
import java.util.concurrent.atomic.AtomicLong;
import software.visionary.counter.Increasing;
var issued = new AtomicLong();
Increasing.Strict<Long> tickets = issued::getAndIncrement;
System.out.println(tickets.next());
System.out.println(tickets.next());
System.out.println(tickets.hasNext());
Output
0
1
true
Dependencies
software.visionary:junit-closure:2026.09.17at Testing
Caveats
- On a counter with no last value,
forEachRemainingnever returns, and neither does a stream over it unless it stops early, aslimit,takeWhileorfindFirstdo.
Views
Drawn from the release. A link in a view opens its source at the release tag.