2
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,

0

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

Comments

5

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.)

1 Comment

Thanks for the great explanation. Here is article that might be useful as well: code.tutsplus.com/tutorials/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.