Функции высшего порядка Java8 и функциональная совместимость Kotlin Lambdas - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть пример Java, где метод реализован как

@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 на Kotlin:

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
    }
}

(Я сделал тип элементов явным и изменилвернуться к 0.0)

Тем не менее я вижу, что есть проблемы совместимости с Java-функциями и родными лямбдами Kotlin, но я не настолько знаком с ними.Ошибка:

enter image description here

Вопрос: возможно ли в Kotlin переопределить метод fitness () внешней библиотеки Java в этом примере, и если да, то как?

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Проблема:

Вы возвращаете (котлинскую) лямбду ISeq<Knapsack.Item> -> Double.Но это не то, что вы хотите.Вы хотите вернуть Java Function<ISeq<Knapsack.Item>, Double>.

Решение:

Вы можете использовать SAM Conversion для создания Function.

Так же, как Java 8, Kotlin поддерживает преобразования SAM.Это означает, что литералы функций Kotlin могут автоматически преобразовываться в реализации интерфейсов Java с помощью одного метода, не используемого по умолчанию, при условии, что типы параметров метода интерфейса соответствуют типам параметров функции Kotlin.

Я создал минимальный пример, чтобы продемонстрировать это.Предположим, у вас есть такой класс Java:

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

Если вы хотите переопределить getFunction в Kotlin, вы бы сделали это следующим образом:

class Bar: Foo() {
    override fun getFunction(): Function<String, Int> {
        return Function {
            it.toInt()
        }
    }
}
0 голосов
/ 21 февраля 2019

Возвращая лямбду в качестве функционального интерфейса Java, вы должны использовать явный конструктор SAM:

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
    }
}

Также не забудьте импортировать java.util.function.Function, поскольку у Kotlin есть собственный класс с таким именем

...