Kotlin is a powerful language that reduces a lot of boilerplate code required to perform basic operations in comparison to Java. The classic examples for the same are any
, non
and all
functions which were added to the Iterable interface and Map interface.
Let try to understand what do they do, why they are required and when to use them. But before we begin, I am assuming a basic knowledge of Map
, Set
and List
.
Any Set
or List
implementation implements Collection
interface (indirectly) which extends Iterable
and any Map
implementation implement Map
interface. All three of them are used to store similar data types with different benefits among the three.
The List
provides the functionality to maintain the ordered collection. whereas Set
and Map
don’t provide the ordering. Both of them provides uniqueness but Map
is a key-value pair mapping.
In short, all three of them are used to store data/objects of similar types.
Since the collection is involved, filtering will be required to iterate the data faster.
To make this filter easier, Kotlin has added a few functions as an extension function to Iterable
as well as Map
.
Let look at them one by one.
Any
Any
is a function that is added as an extension to Iterable
and Map
interfaces, which take a higher-order function as param to predicate the condition and return Boolean
as true, if any of the items in List
, Set
or Map
confirms that condition, else return false.
val list = listOf("one", "two", "three", "four")
val set = setOf("one", "two", "three", "four")
val map = mapOf(1 to "one", 2 to "two", 3 to "three", 4 to "four")
println(list.any { it.endsWith("e") }) // true
println(set.any { it.endsWith("e") }) // true
println(map.any { it.value.endsWith("e") }) // true
Let’s look at the extension function any
, defined in Kotlin
/**
* Returns `true` if at least one element matches the given [predicate].
*
* @sample samples.collections.Collections.Aggregates.anyWithPredicate
*/
public inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean {
if (this is Collection && isEmpty()) return false
for (element in this) if (predicate(element)) return true
return false
}
/**
* Returns `true` if at least one entry matches the given [predicate].
*
* @sample samples.collections.Collections.Aggregates.anyWithPredicate
*/
public inline fun <K, V> Map<out K, V>.any(predicate: (Map.Entry<K, V>) -> Boolean): Boolean {
if (isEmpty()) return false
for (element in this) if (predicate(element)) return true
return false
}
None
Similar to Any
, None
is a function that is added as an extension to Iterable
and Map
interfaces, which also takes a higher-order function as param to predicate the condition and return Boolean
as true if none of the items in List
, Set
or Map
confirms that condition, else return false.
val list = listOf("one", "two", "three", "four")
val set = setOf("one", "two", "three", "four")
val map = mapOf(1 to "one", 2 to "two", 3 to "three", 4 to "four")
println(list.none { it.endsWith("e") }) //false
println(set.none { it.endsWith("e") }) //false
println(map.none { it.value.endsWith("e") }) //false
Let’s look at the extension function none
, defined in Kotlin
/**
* Returns `true` if no elements match the given [predicate].
*
* @sample samples.collections.Collections.Aggregates.noneWithPredicate
*/
public inline fun <T> Iterable<T>.none(predicate: (T) -> Boolean): Boolean {
if (this is Collection && isEmpty()) return true
for (element in this) if (predicate(element)) return false
return true
}
/**
* Returns `true` if no entries match the given [predicate].
*
* @sample samples.collections.Collections.Aggregates.noneWithPredicate
*/
public inline fun <K, V> Map<out K, V>.none(predicate: (Map.Entry<K, V>) -> Boolean): Boolean {
if (isEmpty()) return true
for (element in this) if (predicate(element)) return false
return true
}
All
Similar to Any
and None
, All
is a function that is added as an extension to Iterable
and Map
interfaces, which also takes a higher-order function as param to predicate the condition and return Boolean
as true if all of the items in List
, Set
or Map
confirms that condition, else return false.
val list = listOf("one", "two", "three", "four")
val set = setOf("one", "two", "three", "four")
val map = mapOf(1 to "one", 2 to "two", 3 to "three", 4 to "four")
println(list.all { it.endsWith("e") }) //false
println(set.all { it.endsWith("e") }) //false
println(map.all { it.value.endsWith("e") }) //false
Let’s look at the extension function all
, defined in Kotlin
/**
* Returns `true` if all elements match the given [predicate].
*
* @sample samples.collections.Collections.Aggregates.all
*/
public inline fun <T> Iterable<T>.all(predicate: (T) -> Boolean): Boolean {
if (this is Collection && isEmpty()) return true
for (element in this) if (!predicate(element)) return false
return true
}
/**
* Returns `true` if all entries match the given [predicate].
*
* @sample samples.collections.Collections.Aggregates.all
*/
public inline fun <K, V> Map<out K, V>.all(predicate: (Map.Entry<K, V>) -> Boolean): Boolean {
if (isEmpty()) return true
for (element in this) if (!predicate(element)) return false
return true
}
Any and None without any params
Any
and None
functions also have an overload to both Iterable
and Map
interfaces which don’t take any param but just check if the collection is empty or not.
Any
returns true if the collection is not empty whereas None
return true if the collection is empty.
val list = listOf("one", "two", "three", "four")
val set = setOf("one", "two", "three", "four")
val map = mapOf(1 to "one", 2 to "two", 3 to "three", 4 to "four")
println(list.any()) //true
println(set.any()) //true
println(map.any()) //true
println(list.none()) //false
println(set.none()) //false
println(map.none()) //false
Let’s look at the extension functions, defined in Kotlin
/**
* Returns `true` if collection has at least one element.
*
* @sample samples.collections.Collections.Aggregates.any
*/
public fun <T> Iterable<T>.any(): Boolean {
if (this is Collection) return !isEmpty()
return iterator().hasNext()
}
/**
* Returns `true` if map has at least one entry.
*
* @sample samples.collections.Collections.Aggregates.any
*/
public fun <K, V> Map<out K, V>.any(): Boolean {
return !isEmpty()
}
/**
* Returns `true` if the collection has no elements.
*
* @sample samples.collections.Collections.Aggregates.none
*/
public fun <T> Iterable<T>.none(): Boolean {
if (this is Collection) return isEmpty()
return !iterator().hasNext()
}
/**
* Returns `true` if the map has no entries.
*
* @sample samples.collections.Collections.Aggregates.none
*/
public fun <K, V> Map<out K, V>.none(): Boolean {
return isEmpty()
}
Benefits of using these functions
There is no difference in the implementation but since these are inbuild inline function, you don’t have to write the entire iteration and condition check on your own. Please note that there is no difference in time or space complexity also.
The only reason I wrote about this as a blog is because I feel I am lazy and prefers to use all inbuild functions to write fewer lines of code. :) These were a few of them.