Kotlin功能接口Java兼容性

时间:2018-08-05 09:28:51

标签: java function lambda interface kotlin

我在kotlin上开发应用程序,但是需要良好的Java支持。 我发现的问题是kotlin的功能。

这是我以前做的

fun test(loader: (String) -> Int)

但是它将从kotlin库编译成Function1,并且由于jar的大小,我没有在jar中直接包含kotlin库,这使Java开发人员更加困难,因为他们必须下载kotlin库才能使用这种方法。

我尝试使用java的Supplier或Function接口,但是我发现kotlin开发人员要困难得多,因为您必须提供更多的变量类型和null检查以及泛型参数,这很痛苦。.

还尝试创建自己的界面,例如

@FunctionalInterface
interface Function<in T, out R>: Function<R> {
    operator fun invoke(p: T): R
}

和功能

fun test(loader: Function<String, Int>)

但与默认的Java Function接口相同

所以唯一可行的方法是让编译器将我的原始函数编译为我自己的函数接口,而不是kotlin的函数接口。但是我不知道该怎么做。

3 个答案:

答案 0 :(得分:5)

您面临的问题是由于缺少SAM转换,有关更多信息,请参见[1][2]。简而言之,Java允许您将具有一种非默认,非静态方法的接口视为功能接口。如果Kotlin中存在此转换,则Kotlin Lambda表达式可以隐式转换为Java功能接口,例如Function<T, R>

在不更改编译器的情况下,不可能将函数文字编译为您自己的函数接口。

考虑到现状,您最好的选择是编写一些转换函数,这些函数可以在Kotlin中非常紧凑地完成:

object Functional
{
    @JvmStatic fun <T> toKotlin(supplier: Supplier<T>): () -> T = supplier::get
    @JvmStatic fun <T, R> toKotlin(function: Function<T, R>): (T) -> R = function::apply
    @JvmStatic fun <T> toKotlin(function: BinaryOperator<T>): (T, T) -> T = function::apply
    @JvmStatic fun <T> toKotlin(consumer: Consumer<T>): (T) -> Unit = consumer::accept
    ...
}

让我们将其应用于文件Example.kt:

// passes an argument to the function and returns the result
fun call(function: (Int) -> Int, arg: Int): Int = function(arg)

然后从Java中按如下方式使用它们:

import static yourpackage.Functional.toKotlin;

// in code:
ExampleKt.call(toKotlin(x -> 3 * x), 42);

当然,如果方便是您的目标,那么您可以使用函数参数重载方法,以支持Kotlin和Java方式:

// Kotlin:
fun call(function: (Int) -> Int, arg: Int): Int = function(arg)
fun call(function: Function<Int, Int>, arg: Int): Int = call(toKotlin(function), arg)

// Java:
ExampleKt.call(x -> 3 * x, 42);

答案 1 :(得分:1)

  

这使Java开发人员更加困难,因为他们必须下载kotlin库才能使用此方法

JVM开发人员使用诸如Maven或Gradle之类的构建系统。尝试手动管理依赖项只是一个坏主意。并且如果在实现中使用了任何Kotlin特定类型,则仍然需要Kotlin标准库。

答案 2 :(得分:0)

在kotlin 1.4中,他们增加了定义这样自己的功能接口的功能

struct item{
    char opra; 
    int count;
    double operand;
};
stack<item> S;
double test = S.top.operand;