Thomas Auinger
Thomas Auinger

Reputation: 2095

Filter collection in Kotlin with existing java.util.Predicate instance

I want to filter a collection of values in Kotlin using an instance of a java.util.Predicate implementation, basically something like this:

val predicate = JsQueryPredicate<SportEvent>(query)
schedule.sport_events.filter(predicate)

This doesn't compile though. The following works, is that the recommended way of doing this? Feels a bit cumbersome

val predicate = JsQueryPredicate<SportEvent>(query)
schedule.sport_events.filter { predicate.test(it) }

Upvotes: 2

Views: 752

Answers (2)

Roland
Roland

Reputation: 23242

To answer it more directly: yes... predicate.test(it) or the nearly equivalent method reference predicate::test are the way to go... except...

If you have to deal with Java predicates more often and/or the refactoring of the Java functional types (e.g. Predicate) to Kotlin function types is planned in future, you may also want to add appropriate extension functions instead, e.g.:

fun <T> Iterable<T>.filter(predicate: Predicate<T>) = filter { predicate.test(it) }

With the following usage then:

val javaPredicate : Predicate<String> = Predicate { it == "hello" }
listOf("hello", "world")
        .filter(javaPredicate)

If you replaced the Predicate in future to, e.g. (T) -> Boolean you then don't need to adapt that filter, but just replace/remove the import statement to the extension function.

Extension functions to just transform the Predicate to an appropriate Kotlin function type are possible too, but may not help you that much in future refactorings:

operator fun <T> Predicate<T>.invoke() : (T) -> Boolean = ::test
fun <T> Predicate<T>.transform() : (T) -> Boolean = ::test

Usage samples of those:

val javaPredicate : Predicate<String> = Predicate { it == "hello" }

// variant with Predicate.invoke:
listOf("hello", "world")
    .filter(javaPredicate())

// variant using Predicate.transform()
listOf("hello", "world")
    .filter(javaPredicate.transform())

So I recommend you the overloaded filter-method in case you plan a refactoring or otherwise just stick to filter { predicate.test(it) }/filter(predicate::test), which might make a future refactoring a bit (IDEs help ;-)) harder.

Upvotes: 0

Lino
Lino

Reputation: 19926

You can use a method reference, which gets converted implicitly to a (T) -> Boolean and thus allows you to call the filter method:

schedule.sport_events.filter(predicate::test)

Upvotes: 4

Related Questions