user2123288
user2123288

Reputation: 1119

Java8 Higher-Order Functions and Kotlin Lambdas interoperability

I have a Java example where a method is implemented as

@Override
public Function<ISeq<Item>, Double> fitness() {
    return items -> {
        final Item sum = items.stream().collect(Item.toSum());
        return sum._size <= _knapsackSize ? sum._value : 0;
    };
}

IntelliJ's automatic translation of it to Kotlin is

override fun fitness(): Function<ISeq<Item>, Double> {
    return { items:ISeq<Item> ->
        val sum = items.stream().collect(Item.toSum())
        if (sum.size <= _knapsackSize) sum.value else 0.0
    }
}

(I made the type of items explicit and changed return to 0.0)

Still I see that there are compatibility problems with Java's Function and Kotlin native lambdas, but I'm not that the most familiar with these. Error is:

enter image description here

Question is: is it possible to override in Kotlin the external Java library's fitness() method on this example and if so how ?

Upvotes: 2

Views: 842

Answers (2)

Willi Mentzel
Willi Mentzel

Reputation: 29844

Problem:

You are returning a (Kotlin) lambda ISeq<Knapsack.Item> -> Double. But this is not what you want. You want to return a Java Function<ISeq<Knapsack.Item>, Double>.

Solution:

You can use a SAM Conversion to create a Function.

Just like Java 8, Kotlin supports SAM conversions. This means that Kotlin function literals can be automatically converted into implementations of Java interfaces with a single non-default method, as long as the parameter types of the interface method match the parameter types of the Kotlin function.

I created a minimal example to demonstrate that. Consider you have a Java class like this:

public class Foo {
    public Function<String, Integer> getFunction() {
        return item -> Integer.valueOf(item);
    }
}

If you want to override getFunction in Kotlin you would do it like this:

class Bar: Foo() {
    override fun getFunction(): Function<String, Int> {
        return Function {
            it.toInt()
        }
    }
}

Upvotes: 3

Radosław Panuszewski
Radosław Panuszewski

Reputation: 536

When returning lambda as Java's functional interface, you have to use explicit SAM constructor:

override fun fitness(): Function<ISeq<Item>, Double> {
    return Function { items:ISeq<Item> ->
        val sum = items.stream().collect(Item.toSum())
        if (sum.size <= _knapsackSize) sum.value else 0.0
    }
}

Also don't forget to import java.util.function.Function since Kotlin has its own class of that name

Upvotes: 1

Related Questions