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

如果我有Kotlin功能

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

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

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

这看起来很丑陋。 为什么我不能像f(i -> dosomething());那样写它f(i -> dosomething()); ,因为Kotlin中的Unit相当于Java中的void

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设计师决定放弃功能接口的重复,而是依靠编译器“魔术”。 如果你在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语句/表达式。