Why do I have to return Unit.INSTANCE when implementing in Java a Kotlin function that returns a Unit?

╄→尐↘猪︶ㄣ 提交于 2019-12-17 16:04:22

问题


If I have a Kotlin function

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

and I want to call f from Java, I have to do it like:

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

which looks very ugly. Why can't I just write it like f(i -> dosomething());, since Unit in Kotlin is equivalent to void in Java?


回答1:


Unit in Kotlin is mostly equivalent to void in Java, however only when the rules of the JVM allow it.

Functional types in Kotlin are represented by interfaces like:

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

When you declare (Int) -> Unit, from Java's point of view this is equivalent to Function<Integer, Unit>. That's why you have to return a value. To work around this problem, in Java there are two separate interfaces Consumer<T> and Function<T, R> for when you don't have/have a return value.

The Kotlin designers decided to forgo the duplication of functional interfaces and instead rely on compiler "magic". If you declare a lambda in Kotlin, you don't have to return a value because the compiler will insert one for you.

To make your life a little bit easier, you can write a helper method that wraps a Consumer<T> in a Function1<T, Unit>:

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

Usage:

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

Fun fact: The special handling of Unit by the Kotlin compiler is the reason you can write code like:

fun foo() {
    return Unit
}

or

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

Both methods have return type void in the generated bytecode but the compiler is smart enough to figure that out and allow you to use return statements/expressions anyway.




回答2:


I use this approach for Kotlin & Java. The methods of MyKotlinClass you will see in Java, in Kotlin you will see both methods (class method + extension function).

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


来源:https://stackoverflow.com/questions/37828790/why-do-i-have-to-return-unit-instance-when-implementing-in-java-a-kotlin-functio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!