为什么在Java中实现返回单元的Kotlin函数时必须返回Unit.INSTANCE?

时间:2016-06-15 07:28:33

标签: java kotlin kotlin-interop

如果我有Kotlin功能

fun f(cb: (Int) -> Unit)

我希望从Java调用f,我必须这样做:

f(i -> {
     dosomething();
     return Unit.INSTANCE;
});

看起来非常难看。为什么我不能像f(i -> dosomething());那样编写它,因为Kotlin中的Unit等同于Java中的void

2 个答案:

答案 0 :(得分:39)

Kotlin中的

Unit大部分相当于Java中的void,但只有当JVM的规则允许时才这样。

Kotlin中的功能类型由以下接口表示:

public interface Function1<in P1, out R> : Function<R> {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}

当您声明(Int) -> Unit时,从Java的角度来看,这相当于Function<Integer, Unit>。这就是你必须返回一个值的原因。要解决此问题,在Java中有两个单独的接口Consumer<T>Function<T, R>,用于当您没有/具有返回值时。

Kotlin设计师决定放弃功能界面的重复,而是依赖编译器&#34; magic&#34;。如果在Kotlin中声明lambda,则不必返回值,因为编译器会为您插入一个。

为了让您的生活更轻松,您可以编写一个帮助方法,将Consumer<T>包裹在Function1<T, Unit>中:

public class FunctionalUtils {
    public static <T> Function1<T, Unit> fromConsumer(Consumer<T> callable) {
        return t -> {
            callable.accept(t);
            return Unit.INSTANCE;
        };
    }
}

用法:

f(fromConsumer(integer -> doSomething()));

有趣的事实:Kotlin编译器对Unit的特殊处理是您编写代码的原因:

fun foo() {
    return Unit
}

fun bar() = println("Hello World")

两个方法在生成的字节码中都有返回类型void,但编译器足够智能,可以解决这个问题,并允许您使用return语句/表达式。

答案 1 :(得分:0)

我将这种方法用于Kotlin和Java。您将在Java中看到MyKotlinClass的方法,在Kotlin中将看到这两种方法(类方法+扩展功能)。

MyKotlinClass {

  //Method to use in Java, but not restricted to use in Kotlin.
    fun f(cb: Consumer<Int>) { //Java8 Consumer, or any custom with the same interface
      int i = getYourInt()
      cb.accept(i)
    }
}

//Extension for Kotlin. It will be used in Kotlin.
fun MyKotlinClass.f(cb: (Int) -> Unit) {
    f(Consumer { cb(it) })
}