如果我有Kotlin功能
fun f(cb: (Int) -> Unit)
我希望从Java调用f
,我必须这样做:
f(i -> {
dosomething();
return Unit.INSTANCE;
});
看起来非常难看。为什么我不能像f(i -> dosomething());
那样编写它,因为Kotlin中的Unit
等同于Java中的void
?
答案 0 :(得分:39)
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) })
}