In Kotlin, you can get the maximum value very easily by using the maxBy extension function defined in Collections.kt.
Below is the code that prints the name of the oldest person in the Person object.
val personList = listOf(Person("John", 20), Person("Lee", 21))
personList.maxBy(Person::age)?.run {
// Lee
println(name)
}
This article explains how the maxBy function works.
The maxBy function receives an object and receives a lambda expression that returns an object as a parameter.
The code below passes a lambda expression that receives a Person object to the maxBy function and returns an Int as a parameter.
val resultPerson = personList.maxBy({
person: Person -> person.age
})
A lambda expression is rarely used as it is, and most of the statements are abbreviated.
The following describes how to use a shortened lambda expression passed to the maxBy function.
First, the code below is the code with the data type removed from the lambda expression.
Even if there is no data type, Compiler can infer the data type, so it can be omitted.
val resultPerson = personList.maxBy({
person -> person.age
})
If there is only one parameter, it can be replaced with it
val resultPerson = personList.maxBy({
it -> it.age
})
it can be omitted
val resultPerson = personList.maxBy({
it.age
})
If a lambda expression is the last argument of a function, it can be moved after parentheses.
val resultPerson = personList.maxBy{
it.age
}
val resultPerson = personList.maxBy(Person::age)
Now you have the same code you used in the beginning.
In summary, the value passed to the maxBy parameter that was written at the beginning is an abbreviated expression of a lambda expression that receives a Person object and returns an Int as a method reference.
Next, let's check the code to get the maximum value by passing a lambda expression.
The maxBy function is implemented in Collections.kt.
The code below is the source code of the maxBy function implemented in Collections.kt.
public inline fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T? {
val iterator = iterator()
if (!iterator.hasNext()) return null
var maxElem = iterator.next()
if (!iterator.hasNext()) return maxElem
var maxValue = selector(maxElem)
do {
val e = iterator.next()
val v = selector(e)
if (maxValue < v) {
maxElem = e
maxValue = v
}
} while (iterator.hasNext())
return maxElem
}
The code converted from Kotlin source to Java is as follows
@Nullable
public static final Object myMaxBy(@NotNull Iterable $this$myMaxBy, @NotNull Function1 selector1) {
Intrinsics.checkParameterIsNotNull($this$myMaxBy, "$this$myMaxBy");
Intrinsics.checkParameterIsNotNull(selector1, "selector1");
Iterator iterator = $this$myMaxBy.iterator();
if (!iterator.hasNext()) {
return null;
} else {
Object maxElem = iterator.next();
if (!iterator.hasNext()) {
return maxElem;
} else {
Comparable maxValue = (Comparable)selector1.invoke(maxElem);
do {
Object e = iterator.next();
Comparable v = (Comparable)selector1.invoke(e);
if (maxValue.compareTo(v) < 0) {
maxElem = e;
maxValue = v;
}
} while(iterator.hasNext());
return maxElem;
}
}
}
Let's take a look at the Java source and analyze the Kotlin source partly.
Let's check the maxBy function format first.
As described above, maxBy receives a Person object and receives a lambda expression that returns an Int and returns a Person object.
And what you can additionally check in the code below is that maxBy is an extension function of the Iterable class.
Therefore, an object implementing Iterable can use the maxBy extension function.
public inline fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T? {
The code below handles the case where the Iterable object is empty and there is only one.
It's not an important part, so let's check it lightly
Handling code when object is empty
val iterator = iterator()
if (!iterator.hasNext()) return null
Processing code when there is only one object
var maxElem = iterator.next()
if (!iterator.hasNext()) return maxElem
Below is the core couple of the code-named maxBy function that compares several objects and returns the object with the maximum value.
The code starts with the first Person object of Iterable stored in maxElem.
var maxValue = selector(maxElem)
do {
val e = iterator.next()
val v = selector(e)
if (maxValue < v) {
maxElem = e
maxValue = v
}
} while (iterator.hasNext())
return maxElem
Selector is a lambda expression that is used in the starting area and loop and passed to the maxBy function.
When the lambda expression is executed, the Person object is used as the first Person object of the Iterable stored in maxElem, and the Int value of the first Person object is stored in maxValue.
Since the maxBy function uses Generic, maxElem and maxValue will be appropriately converted and processed according to the lambda expression.
Anyway, in our code, maxElem is a Person object and maxValue is an Int type value.
Now, using the selector in the loop, the lambda expression is executed on all objects and the object with the maximum value is returned as a return value.