ant2009
ant2009

Reputation: 22696

converting a java method to kotlin. Return a lambda expression

kotlin 1.3.31

I have the following code snippet in Java that I am trying to convert to Kotlin

private ArgumentMatcher<List<Person> customArgumentMatcher(final int size) {
    return argument -> argument.size() == size;
}

My understanding of the above is a method declaration that has a ArgumentMatcher as the return type and the method of the interface is executed in the lambda expression and the resulting boolean is returned. Correct me if I am wrong with my explanation.

However, when I try and convert this to Kotlin

 private fun customArgumentMatcher(size: Int): ArgumentMatcher<List<Person>> {
    return { argument -> argument.size == size }
 }

I get the following error:

Required ArgumentMatcher<List<Person>>
found: (???) -> Boolean

Many thanks for any suggestions,

Upvotes: 2

Views: 282

Answers (2)

Slaw
Slaw

Reputation: 46275

Since ArgumentMatcher is a Java functional interface you need to use:

fun customArgumentMatcher(size: Int): ArgumentMatcher<List<Person>> {
    return ArgumentMatcher { argument -> argument.size == size }
}

See the SAM Conversions section of the Kotlin reference.


You could also use:

fun customArgumentMatcher(size: Int) = ArgumentMatcher<List<Person>> { it.size == size }

See gidds' answer for some background on why the above syntax is necessary.

Upvotes: 5

gidds
gidds

Reputation: 18627

To add some background to the other answer:

This is one of the slightly awkward areas in Kotlin, as far as Java interoperability goes.  But it's an unfortunate consequence of Kotlin being a better language in itself!  Let me try to explain…

When Java added lambdas, they did it in a way (as with generics before that) to make the bare minimum of changes to the way the language worked.  So they didn't make functions first-class types.  Instead, they enshrined the existing practice of using interfaces.  For example, if you wanted something to be informed of ActionEvents, you'd implement the ActionListener interface.  This has a single method called actionPerformed() taking an ActionEvent parameter.

They didn't want to change how any of that worked, so in Java 8+, a lambda is simply a more concise way of implementing some interface.  The context (i.e. the method you're calling, or the type of variable you're assigning it to) tells the compiler what type of interface you want — it must be a ‘functional interface’ with a Single Abstract Method (SAM) — and then the compiler generates an implementation.  There are a few optimisations, but it's basically what you used to do in Java 7-.  It doesn't work too badly, but there are a lot of awkward corner cases, because functions aren't full first-class objects.

Kotlin, on the other, does have proper function types.  This is much more powerful and flexible, but doesn't match Java's way of doing things.

The Kotlin compiler has some special cases allowing a lambda to be automatically converted into an implementation of a Java SAM interface.  (This doesn't apply when implement Kotlin interfaces, though, which causes some confusion.)

In cases where you're passing a SAM-implementing lambda directly to a method, the compiler can infer its type.  (As in @Slaw's second example.)

But in other cases, you need to specify the interface name before the opening brace.  (As in @Slaw's first example.)

Upvotes: 5

Related Questions