I am currently trying to compare Java lambdas with Kotlin lambdas. I think it is a advantage that kotlin doesnt need Functional Interfaces for creating a lambda. I think it is a little bit different to get an overview of all Funtional Interfaces in Java to use lambdas and collection manipulation very well.
But I found a negative point also during my research. I think a Predicate in Java has a default function and which lets you combine some lambdas.
So you can do something like this in Java:
final Predicate<Person> isAdult = person -> person.getAge() >= 18;
final Predicate<Person> isMale = person -> person.getGender() == Gender.MALE;
// Combine
final Predicate<Person> isAdultAndMale = isAdult.and(isMale);
I think there is now equivalent in Kotlin. I read in Head first Kotlin that there is a combine function. But it doesn't work in the Kotlin playground. So I end up with an extension function. Respectively with two extension functions. One for two lambdas and another for more than two lambdas and with varargs.
enum class Gender{MALE, FEMALE}
enum class EyeColor{BLUE, GREEN}
data class Person(
var name: String,
var age: Int,
var gender: Gender,
var eyeColor: EyeColor
)
fun List<Person>.combineTwoLambdas(firstLambda: (Person) -> Boolean, secondLambda: (Person) -> Boolean): List<Person> {
return this.filter(firstLambda).filter(secondLambda)
}
fun List<Person>.combineMoreLambdas(vararg personFilters: (Person) -> Boolean): List<Person> {
var myPersons = listOf<Person>()
personFilters.forEach {
myPersons = this.filter(it)
}
return myPersons
}
typealias PredicatePersons = (Person) -> Boolean
fun main() {
val persons = listOf(
Person("Susi", 20, Gender.FEMALE, EyeColor.BLUE),
Person("Ralf", 19, Gender.MALE, EyeColor.BLUE),
Person("Michael", 20, Gender.MALE, EyeColor.GREEN))
val isAdult: (Person) -> Boolean = {person -> person.age >= 18}
val isMale: (Person) -> Boolean = {it.gender == Gender.MALE}
val hasGreenEyes: PredicatePersons = {it.eyeColor == EyeColor.GREEN}
// combine two lambdas
val isAdultAndMale = persons.combineTwoLambdas(isAdult, isMale)
// combine more than two lambdas
val isAdultAndMaleAndHasGreenEyes = persons.combineMoreLambdas(isAdult, isAdult, hasGreenEyes)
print("combine all ${isAdultAndMaleAndHasGreenEyes}")
}
Is it somehow easier to chain multiple lambdas? Thanks.
UPDATE
Here is an update. Thanks to @Sweeper
val isAdultAndMale: (Person) -> Boolean = {isAdult(it) && isMale(it)}
// with alias
val isAdultAndMale: PredicatePersons = {isAdult(it) && isMale(it)}
{ predictate1(it) && predicate2(it) }
) is concise enough, don't you think? Unlike in Java, where you need.apply
all over the place. - Sweeper