T
- object type of this countablepublic interface Countable<T> extends java.lang.Iterable<T>, Sizeable
Having a known size usually helps in optimization, e.g. when copying.
This is meant to be used as a read-only interface, although Iterable
basically exports mutability via Iterator.remove()
.
This interface extends Iterable
nevertheless so
implementations can be used in enhanced for
loops.
In an ideal world Java collections should implement this interface to provide
a better compile-time read-only access compared to the
Collections#unmodifiableCollection()
which will result
in runtime errors when mutating.
To allow living in a standard Java environment this interface provides
methods asCollection()
to view it as an unmodifiable
collection and viewCollection(Collection)
allowing
to view a collection as Countable
.
A countable can also view an array or part of it (viewArray(Object[])
and viewArray(Object[], int, int)
), and can be converted to
an array.
Last not least an empty countable
is useful sometimes.
Modifier and Type | Interface and Description |
---|---|
static class |
Countable.Base<TT>
Abstract base class which provides useful implementations
for
Object.equals(Object) , Object.hashCode() ,
Object.toString() . |
Modifier and Type | Field and Description |
---|---|
static Countable<java.lang.Object> |
EMPTY
A basic implementation of an empty countable.
|
Modifier and Type | Method and Description |
---|---|
default void |
addAllTo(java.util.Collection<? super T> collection)
Add all entries of this countable to the given collection.
|
default int |
addToArray(T[] array,
int arrayPos)
Add the complete content of this countable to the given array.
|
default Countable.Base<T> |
asBase()
Convert this into a base countable.
|
default java.util.Collection<T> |
asCollection()
View this countable as an unmodifiable standard Java collection.
|
static <E> Countable<E> |
combined(Countable<? extends Countable<? extends E>> parts)
Combine several countables into one.
|
static <E> Countable<E> |
combined(Countable<? extends E>... parts)
Combine several countables into one.
|
default boolean |
containsEq(T elem)
Is the given element contained?
|
default boolean |
containsRef(T elem)
Is the given element contained?
|
static <E> Countable<E> |
downCast(Countable<? extends E> countable)
Downcast a countable of a given type so that it appears at a countable of a super type.
|
static <E> Countable<E> |
empty()
Get an empty countable.
|
static <E1,E2> boolean |
equal(Countable<E1> countable1,
Countable<E2> countable2,
java.util.function.BiPredicate<? super E1,? super E2> equalityChecker)
Are two countables equal?
|
default <E> boolean |
equals(Countable<E> other,
java.util.function.BiPredicate<? super T,? super E> elementEquals)
Does this countable equal another one?
|
default java.lang.Iterable<T> |
filtered(java.util.function.Predicate<? super T> filter)
Get a filtered view of this countable.
|
default Indexable<T> |
filteredToIndexable(java.util.function.Predicate<? super T> filter)
Get an indexable which contains elements from this countable
which fulfill a given filter.
|
default Countable<T> |
filterToCountable(java.util.function.Predicate<? super T> filter)
Get a countable which contains elements from this countable
which fulfill a given filter condition.
|
default T |
first()
Get the first element.
|
default T |
firstOrNull()
Get the first element, or
null if this countable is empty. |
default <V> V |
foldLeft(V initialValue,
java.util.function.BiFunction<? super V,? super T,? extends V> folder)
Calculate a value from this countable by reapplying a 2-argument function for each
element, with the result of the latest application and the current element.
|
default <E extends java.lang.Exception> |
forEachFragile(FragileProcedure1<E,? super T> consumer)
Apply a fragile consumer to each element of this countable.
|
static <TT> Indexable<TT> |
freeze(Countable<? extends TT> countable)
Freeze a countable to an indexable.
|
static <E> Countable<E> |
fromOptional(java.util.Optional<E> optional)
Convert a standard Optional to a Countable with either one or no element.
|
default Indexable<T> |
frozen()
Get a frozen version of this countable.
|
default Indexable<T> |
frozen(java.util.function.Function<? super T,? extends T> elementCloner,
boolean cloneOnGet)
Get a frozen version of this countable.
|
default <K> Dict<K,Indexable<T>> |
groupingBy(java.util.function.Function<? super T,? extends K> keyExtractor)
Create a mapping of a key extracted from each element to groups of elements which belongs to this key.
|
default <K,V> Dict<K,Indexable<V>> |
groupingBy(java.util.function.Function<? super T,? extends K> keyExtractor,
java.util.function.Function<? super T,? extends V> valueMapper)
Create a mapping of a key extracted from each element to groups of elements which belongs to this key.
|
default boolean |
hasAll(java.util.function.Predicate<? super T> check)
Check if all elements fulfill a given predicate.
|
default boolean |
hasAny(java.util.function.Predicate<? super T> check)
Check if any element fulfills a given predicate.
|
default boolean |
isEmpty()
Is this countable empty?
|
default boolean |
isSorted(java.util.Comparator<? super T> order)
Is this countable ordered according to the given sort order?
|
default boolean |
isStrictlySorted(java.util.Comparator<? super T> order)
Is this countable strictly ordered according to the given sort order?
|
default T |
last()
Get the last element.
|
default T |
lastOrNull()
Get the last element, or
null if this countable is empty. |
default <K> Dict<K,T> |
mappingBy(boolean firstWins,
java.util.function.Function<? super T,? extends K> keyExtractor)
Create a mapping of a key extracted from each element to the element itself.
|
default <K,V> Dict<K,V> |
mappingBy(boolean firstWins,
java.util.function.Function<? super T,? extends K> keyExtractor,
java.util.function.Function<? super T,? extends V> valueMapper)
Create a mapping of a key extracted from each element to the element itself.
|
default java.util.Optional<T> |
optFirst()
Get the first element as an Optional.
|
static <E> Countable<E> |
optional(E optionalElement)
Get a countable with a single or no element.
|
default java.util.Optional<T> |
optLast()
Get the first element as an Optional.
|
static <VV> Indexable<Pair<VV>> |
orderedCombination(Countable<VV> countable1,
Countable<VV> countable2,
java.util.Comparator<? super VV> order)
Create an indexable of pairs from two countables which is the combination of pairs from
both countables when ordered.
|
static <E> Countable<E> |
singleton(E singleElement)
Get a countable with a single element.
|
default Indexable<T> |
sorted(java.util.Comparator<? super T> order)
Get a sorted frozen version of this countable.
|
default java.lang.Object[] |
toArray()
Copy the content of this countable to an array.
|
default T[] |
toArray(java.lang.Class<T> type)
Copy the elements of this countable into an array of typed objects and return the result.
|
default java.util.ArrayList<T> |
toList()
Get a list which is the copy of this countable.
|
static java.lang.String |
toString(Countable<?> countable)
Create a string representation of the given countable.
|
static <E> Countable<E> |
uniform(E element,
int count)
Get a countable which is returning the same element multiple times.
|
default <R> Countable<R> |
view(java.util.function.Function<? super T,? extends R> mapper)
View this countable as if it has another type.
|
static <E> Countable<E> |
viewArray(E... elements)
View an array as if it were a countable.
|
static <E> Countable<E> |
viewArray(E[] elements,
int start,
int length)
View a part of an array as if it were a countable.
|
static <E> Countable<E> |
viewCollection(java.util.Collection<? extends E> collection)
View a collection as if it were a countable.
|
static <E,T> Countable<T> |
viewCollection(java.util.Collection<E> collection,
java.util.function.Function<? super E,? extends T> mapper)
Create a read-only view of a collection as if it were a countable of a different type.
|
static <E> Countable<E> |
viewCollectionN(java.util.Collection<? extends E> collection)
View a collection which is potentially
null as if it were a countable. |
static <E,T> Countable<T> |
viewCollectionN(java.util.Collection<E> collection,
java.util.function.Function<? super E,? extends T> mapper)
Create a read-only view of a collection which is possibly
null
as if it were a countable of a different type. |
default <R,E extends java.lang.Exception> |
viewFragile(FragileFunction1<? extends R,E,? super T> mapper)
View this countable as if it has another type using a fragile mapping which might throw a checked exception.
|
default boolean isEmpty()
Sizeable.size()
will return 0
.
This default implementation just checks for Sizeable.size()
returning 0
true
if this countable is empty, false
otherwise.
Because calculating the size might be expensive sometimes in these cases
implementations should override this method if possible.
@NotNull default java.util.Collection<T> asCollection()
Collection
view of this countable@NotNull default java.util.ArrayList<T> toList()
default void addAllTo(@NotNull java.util.Collection<? super T> collection)
collection
- collection where all entries are added@NotNull default java.lang.Object[] toArray()
@NotNull default T[] toArray(@NotNull java.lang.Class<T> type)
type
- array element type, has to match the element type of this indexabledefault int addToArray(@NotNull T[] array, int arrayPos)
array
- array where the content is addedarrayPos
- start position in hte array where the content is added@NotNull default <R> Countable<R> view(@NotNull java.util.function.Function<? super T,? extends R> mapper)
R
- resulting element typemapper
- converter from elements of this countable to elements of the returned countable@NotNull default <R,E extends java.lang.Exception> Countable<R> viewFragile(@NotNull FragileFunction1<? extends R,E,? super T> mapper)
The returned countable is evaluated lazily, so the exception might be triggered much later, of even never if the element where the converted does throw an exception is never used.
If mapper
is throwing an exception this exception is wrapped into a WrappedFragileException
which is thrown instead.
If the resulting countable is only temporarily used, you can wrap its usage with a
try-catch construction (see below). If it is returned from your code the only way
to make the exception appear early is freezing
with the price
of an internal copy.
Example of wrapping the usage (assuming that method Foo foo(Bar)
converts Foo
objects
to Bar
objects with the occasional CheckedException
exception):
try {
Countable<Bar> bars = // ...
try {
Countable<Foo> foos = bars.viewFragile(bar -> foo(bar));
// use foos only inside this block or
// return foos.frozen();
// to trigger possible exceptions inside this block.
} catch(WrappedFragileException x) {
x.rethrow(CheckedException.class); // this will throw the caught exception
// throw new RuntimeException("Never will reach here!");
}
}
R
- target type of the elements of the returned countableE
- possible exception thrown by mapper
mapper
- mapper from incoming to outgoing objects which might throw an exception@NotNull default java.lang.Iterable<T> filtered(@NotNull java.util.function.Predicate<? super T> filter)
filter
- check which defines the elements which are included in the returned Iterbble
.filter
accepts@NotNull default Countable<T> filterToCountable(@NotNull java.util.function.Predicate<? super T> filter)
filtered(Predicate)
this
will create an independent copy.filter
- filter conditian used to select elements of the returned indexable@NotNull default Indexable<T> filteredToIndexable(@NotNull java.util.function.Predicate<? super T> filter)
filtered(Predicate)
this
will create an independent copy.filter
- filter used to select elements of the returned indexabledefault <E extends java.lang.Exception> void forEachFragile(@NotNull FragileProcedure1<E,? super T> consumer) throws E extends java.lang.Exception
E
- exception which the consumer might throwconsumer
- fragile consumer which might throw an exceptionE
- forwarded exception of the consumerE extends java.lang.Exception
default <V> V foldLeft(V initialValue, @NotNull java.util.function.BiFunction<? super V,? super T,? extends V> folder)
V
- result value typeinitialValue
- initial start value used with the first elementfolder
- folding function, will receive the accumulated value as its first argument
and the current element as its second argument@NotNull default Indexable<T> frozen()
Often countables are used as a view to underlying collections.
Although this interface is immutable, the underlying collection might
nevertheless change. This method copies the current state of this countable
into an unmodifiable state, and returns a Countable which is
stable in size and will return always the same elements.
Beware: it is still possible that any element itself changes when the
elements are mutable. Use frozen(Function, boolean)
to take care
of this.
Calling frozen()
again on the returned object will just return
the object itself, so you can safely call this method more than once.
@NotNull static <TT> Indexable<TT> freeze(@NotNull Countable<? extends TT> countable)
frozen()
this method allows to change
the element type to one of its super types. As the view is read-only
this is not a problem.TT
- element type of returned countablecountable
- countable to freeze@NotNull default Indexable<T> sorted(@NotNull java.util.Comparator<? super T> order)
Often Indexables are used as a view to underlying collections.
Although this interface is immutable, the underlying collection might
nevertheless change. This method copies the current state of this countable
into an unmodifiable state, and returns an Indexable which is
sorted, stable in size and will always return the same elements
in the given order.
Beware: it is still possible that any element itself changes when the
elements are mutable. Use frozen(Function, boolean)
and sort afterwards to take care of this.
order
- ordering condition for the returned indexabledefault boolean isSorted(@NotNull java.util.Comparator<? super T> order)
isStrictlySorted(Comparator)
for a check which does not accept that.
Empty or 1-element countables will always return true
.order
- order which is checkedtrue
if the elements in this countable are ordered considering the given order
false
if notdefault boolean isStrictlySorted(@NotNull java.util.Comparator<? super T> order)
isSorted(Comparator)
for a check which is more relaxed.
Empty or 1-element countables will always return true
.order
- order which is checkedtrue
if the elements in this countable are ordered considering the given order
false
if not@NotNull default Indexable<T> frozen(@NotNull java.util.function.Function<? super T,? extends T> elementCloner, boolean cloneOnGet)
Often Countables are used as a view to underlying collections. Although this interface is immutable, the underlying collection might nevertheless change. This copies the current state of this countable into an unmodifiable state, and returns a Countable which is stable in size and will returns always the same elements. This method also takes care of possibly mutable elements, which are copied when freezing and possibly also on getting.
Calling frozen()
again on the returned object will just return
the object itself, but calling this method again will always create a
new object.
elementCloner
- cloner called for each element of this countable to create
the same-position element in the frozen countablecloneOnGet
- make the returned countable clone an element each
time it is requested? If true
elements inside
the returned countable will be protected from mutation with
the price of creating a copy on each request.default T first()
java.util.NoSuchElementException
- if this countable is emptyfirstOrNull()
,
optFirst()
@Nullable default T firstOrNull()
null
if this countable is empty.
Note that this method is dubious for countables which could contain null
elements.null
if this countable is emptyfirst()
,
optFirst()
@NotNull default java.util.Optional<T> optFirst()
NullPointerException
if the first element is null
elements.java.lang.NullPointerException
- if first element is null
first()
,
firstOrNull()
default T last()
lastOrNull()
,
optLast()
default T lastOrNull()
null
if this countable is empty.
In the base implementation iterates over all elements in this countable
to reach the last element.
Note that this method is dubious for countables which could contain null
elements.@NotNull default java.util.Optional<T> optLast()
NullPointerException
if the last element is null
elements.java.lang.NullPointerException
- if last element is null
last()
,
lastOrNull()
default boolean containsEq(T elem)
Objects.deepEquals(Object, Object)
for checking whether an
element is contained.elem
- element to check fortrue
if the element is contained in this countablefalse
if notcontainsRef(Object)
default boolean containsRef(T elem)
elem
- element to check fortrue
if the element is contained in this countablefalse
if notcontainsEq(Object)
default boolean hasAny(@NotNull java.util.function.Predicate<? super T> check)
check
- predicate to checktrue
if the predicate tested true
on any elementfalse
if it tested false
on all elementsdefault boolean hasAll(@NotNull java.util.function.Predicate<? super T> check)
Note that as this basically checks for misses an empty countable will return
always return true
. If this is an issue, add a check for emptiness.
check
- predicate to checktrue
if the predicate tested true
on all elementfalse
if it tested false
on any element@NotNull default <K> Dict<K,Indexable<T>> groupingBy(@NotNull java.util.function.Function<? super T,? extends K> keyExtractor)
K
- grouping key typekeyExtractor
- key extractor which defines the key for a given element in this countableDict.frozen()
to the result if it is not temporary.@NotNull default <K,V> Dict<K,Indexable<V>> groupingBy(@NotNull java.util.function.Function<? super T,? extends K> keyExtractor, @NotNull java.util.function.Function<? super T,? extends V> valueMapper)
K
- grouping key typeV
- value type of the resulting groupskeyExtractor
- key extractor which defines the key for a given element in this countablevalueMapper
- mapper which converts the elements of this countable to the element type of the
returned groupsDict.frozen()
to the result if it is not temporary.@NotNull default <K> Dict<K,T> mappingBy(boolean firstWins, @NotNull java.util.function.Function<? super T,? extends K> keyExtractor)
firstWins
defines
whether the first is kept or overwritten.
Use groupingBy(Function)
if you want to keep all values.
K
- key typefirstWins
- if true
the first element which resolves to a given key
is kept, all others are discarded, if false
the last
element which resolves to a key is keptkeyExtractor
- key extractor which defines the key for a given element in this countable@NotNull default <K,V> Dict<K,V> mappingBy(boolean firstWins, @NotNull java.util.function.Function<? super T,? extends K> keyExtractor, @NotNull java.util.function.Function<? super T,? extends V> valueMapper)
firstWins
defines
whether the first is kept or overwritten.
Use groupingBy(Function, Function)
if you want to keep all values.
K
- key typeV
- value type returned mappingfirstWins
- if true
the first element which resolves to a given key
is kept, all others are discarded, if false
the last
element which resolves to a key is keptkeyExtractor
- key extractor which defines the key for a given element in this countablevalueMapper
- mapper which converts the elements of this countable to the element type of the
returned groups@NotNull default Countable.Base<T> asBase()
Object.equals(Object)
, Object.hashCode()
,
and Object.toString()
.default <E> boolean equals(@NotNull Countable<E> other, @NotNull java.util.function.BiPredicate<? super T,? super E> elementEquals)
This method is more flexible than standard Object.equals(Object)
because it allows to define the check for element equality.
It's using equal(Countable, Countable, BiPredicate)
to perform the check
and therefore follows its invariants.
E
- element type of other countableother
- other countableelementEquals
- check for element equalitytrue
if this and the other countable are considered equal regarding the given element checkfalse
if not@NotNull static <E> Countable<E> viewCollection(@NotNull java.util.Collection<? extends E> collection)
As this is a view any changes in the underlying collection
will be reflected from the returned Countable
.
If this may pose a problem copy the collection first:
Countable.viewCollection(new ArrayList<>(collection));
E
- element type of the returned countable, which because of the
read-only nature of this interface can be any super-type of
the collection's element typecollection
- collection to viewcollection
@NotNull static <E> Countable<E> viewCollectionN(@Nullable java.util.Collection<? extends E> collection)
null
as if it were a countable.
This creates read-only access to the underlying collection.
As this is a view any changes in the underlying collection
will be reflected from the returned Countable
.
If this may pose a problem copy the collection first:
or call frozen() on the returned countableCountable.viewCollection(new ArrayList<>(collection));
E
- element type of the returned countable, which because of the
read-only nature of this interface can be any super-type of
the collection's element typecollection
- collection to viewcollection
, empty
if collection
is null
@NotNull static <E,T> Countable<T> viewCollection(@NotNull java.util.Collection<E> collection, @NotNull java.util.function.Function<? super E,? extends T> mapper)
As this is a view any changes in the underlying collection
will be reflected from the returned Countable
.
If this may pose a problem copy the collection first:
or call frozen() on the returned countable.Countable.viewCollection(new ArrayList<>(collection), mapper);
E
- element type of the incoming collectionT
- element type of the returned countablecollection
- collection to viewmapper
- mapper which turns the elements of the incoming collection into
the elements of the countablecollection
viewCollection(Collection)
@NotNull static <E,T> Countable<T> viewCollectionN(@Nullable java.util.Collection<E> collection, @NotNull java.util.function.Function<? super E,? extends T> mapper)
null
as if it were a countable of a different type.
This creates a read-only access to the underlying collection which represents
its elements in a different way.
Besides of the handling of null
this behaves the same as
viewCollection(Collection, Function)
, for null
this returns the empty countable.E
- element type of the incoming collectionT
- element type of the returned countablecollection
- collection to viewmapper
- mapper which turns the elements of the incoming collection into
the elements of the countablecollection
, empty for null
@NotNull @SafeVarargs static <E> Countable<E> viewArray(@NotNull E... elements)
As this is a view any changes in the underlying array
will be reflected by the returned Countable
.
If this may pose a problem copy the array first:
Countable.viewCollection(array.clone());
E
- array element type, also element type of returned countableelements
- array of elements@NotNull static <E> Countable<E> viewArray(@NotNull E[] elements, int start, int length)
As this is a view any changes in the underlying array
will be reflected by the returned Countable
.
If this may pose a problem copy the array first:
Countable.viewCollection(Arrays.copyOfRange(elements, start, start + length));
E
- array element type, also element type of returned countableelements
- array of elementsstart
- start index of represented elements of arraylength
- number of elements represented from array@NotNull static <E> Countable<E> downCast(@NotNull Countable<? extends E> countable)
E
- target type of returned countablecountable
- coubtable to be downcasted, needs to have a tyoe which extends or implements <E>
countable
, but using a different element type@NotNull static <E> Countable<E> empty()
null
.E
- element type of the returned empty countable@NotNull static <E> Countable<E> singleton(E singleElement)
E
- element type of this countablesingleElement
- single element of this countable@NotNull static <E> Countable<E> optional(@Nullable E optionalElement)
E
- element typeoptionalElement
- optional elementnull
,
or an empty countable if it is null
@NotNull static <E> Countable<E> fromOptional(@NotNull java.util.Optional<E> optional)
E
- optional/countable typeoptional
- optional to convert to countable@NotNull static <E> Countable<E> uniform(@NotNull E element, int count)
E
- element typeelement
- element returned from this countable on each next()
call of its iteratorcount
- number of times the same element is returned from the iterator, must not be negativeelement
count
times during iteration@NotNull @SafeVarargs static <E> Countable<E> combined(@NotNull Countable<? extends E>... parts)
E
- element type of resulting countableparts
- countables to be combined@NotNull static <E> Countable<E> combined(@NotNull Countable<? extends Countable<? extends E>> parts)
E
- element type of resulting countableparts
- countables to be combined@NotNull static <VV> Indexable<Pair<VV>> orderedCombination(@NotNull Countable<VV> countable1, @NotNull Countable<VV> countable2, @NotNull java.util.Comparator<? super VV> order)
null
OrderedPair.first
entry if an element from the second
countable does not have a counterpart, or a pair with a null
OrderedPair.second
entry if a given value from the first countable does not have a counterpart.VV
- value typecountable1
- first countablecountable2
- second countableorder
- order applied to the countablesnull
for unmatched entriesstatic <E1,E2> boolean equal(@NotNull Countable<E1> countable1, @NotNull Countable<E2> countable2, @NotNull java.util.function.BiPredicate<? super E1,? super E2> equalityChecker)
Equality is complex, because it depends. This equality check for two countables allows to define how elements are compared. Regardless from that it there are 2 invariants:
E1
- element type of first countableE2
- element type of second countablecountable1
- first countablecountable2
- second countableequalityChecker
- checker for equality of both objectstrue
if both countables contain the same values in the same sequencefalse
if sizes or values differ