简体   繁体   中英

What is the difference between filter () and {} in Kotlin

I am studying Kotlin and facing some difficulties with understanding the difference between filter with parenthesis and curly braces. If I check filter implementation, Intellij redirects me to the same source.

Code example:

listOf("john", "dave").filter { name -> name.startsWith("j") }

// versus

// simple predicate function
fun getSimplePredicate(): (String) -> Boolean = 
  name: String -> name.firstName.startsWith(prefix)

// actual filter call
listOf("john", "dave).filter(getSimplePredicate())

What If I want to call somehow filter { getSimplePredicate() } ?

Is there is a way? And what is the difference? Thanks in advance

filter() expects a predicate function as argument, ie a function which takes a string and returns a boolean.

In Kotlin, if the last argument of a function (filter here) is a function (the predicate), then you can pass a lambda and the lambda can be out of the parentheses. So

.filter { ... }

is the same as

.filter({ ... })

So, in your code, { name -> name.startsWith("j") } is a lambda which is the argument passed to filter() .

The function getSimplePredicate() returns a predicate function.

So .filter(getSimplePredicate()) is equivalent to .filter({ name.firstName.startsWith(prefix) }) , which is equivalent to .filter { name.firstName.startsWith(prefix) } .

.filter { getSimplePredicate() } would be valid if { getSimplePredicate() } was a function that returns a Boolean, ie if getSimplePredicate() returned a Boolean. But it doesn't, so it's not valid.

As JB Nizet mentions, this isn't specific to filtering, but is standard Kotlin syntax. If you're calling a function with a lambda as the last parameter, eg:

list.map({ size -> size * 2 })

Then you can move the lambda outside the parentheses :

list.map(){ size -> size * 2 }

(That's mainly to allow functions that look like new language syntax. But it's useful generally.) And if there's nothing left in them, you can omit the parentheses entirely :

list.map{ size -> size * 2 }

Also, if a lambda has exactly one parameter (and the compiler can infer its type), then you can refer to it as it instead of naming it explicitly:

list.map{ it * 2 }

All four forms mean exactly the same thing : they're calling the map() function with a lambda. (You'll see those sorts of syntactic shortcuts a lot; they can help to make code easier to read.)

OK, on to your code:

Your first line works, but your predicate function needs a few tweaks before it'll compile. The signature is fine, but the definition won't work without braces. (In Scala and Java, the arrow is the distinguishing part; but we've just seen how you can omit that in Kotlin, so every lambda must have braces .)

Also, you haven't defined firstName or prefix . I'm going to assume that we can ignore the former, and provide the latter as a parameter. With a bit of simplification, that gives:

fun getSimplePredicate(prefix: String): (String) -> Boolean
    = { it.startsWith(prefix) }

And with those tweaks, you can indeed use it to provide a predicate for filtering , eg:

listOf("john", "dave").filter(getSimplePredicate("j"))

(Note that this time, there are no curly braces, as we're not creating a lambda in this line — the function has already done that.)

Of course, in this case, it's actually simpler to provide a lambda directly, as per your first example! But this illustrates the principle.

There's one other option that's worth covering, too, which is a function reference. If you already had a function that would do the job, you don't need to put it in a lambda, but can refer to it directly, using the :: notation. For example:

fun hasValidPrefix(s: String) = s.startsWith("j")

listOf("john", "dave").filter(::hasValidPrefix)

That only works if the parameter type(s) are compatible, but it's slightly simpler (and can generate slightly more efficient bytecode).

All of these are explained in the Kotlin docs .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM