简体   繁体   English

如何为 Java 调用者声明返回类型为“void”的 Kotlin Lambda?

[英]How to declare a Kotlin Lambda with return type 'void' for a java caller?

I have a library that is completely written in Kotlin including its public API.我有一个完全用 Kotlin 编写的库,包括它的公共 API。 Now a user of the library uses Java, the problem here is that Kotlin Lambdas with return type Unit are not compiled to return type void .现在该库的用户使用 Java,这里的问题是具有返回类型Unit的 Kotlin Lambda 未编译为返回类型void The effect is that the Java side has always to return Unit.INSTANCE for methods that are effectivly void .结果是 Java 端必须始终为有效void的方法返回Unit.INSTANCE Can this be avoided somehow?这可以以某种方式避免吗?

Example:例子:

Kotlin Lambda科特林拉姆达

interface Foo{
  fun bar(x:(String)->Unit)
}

Java call Java调用

public void call(){
   foo.bar(this::processString)
}

//the return type should rather be void instead of Unit
public Unit processString(String s){  
    return Unit.INSTANCE 
    // ^^ implementations should not be forced to return anything 
 }

Is it possible to declare the Kotlin Lambda differently so the compiler generates a void return type?是否可以以不同方式声明 Kotlin Lambda,以便编译器生成void返回类型?

see also How to declare a Kotlin function with return type 'void' for a java caller?另请参阅如何为 Java 调用者声明返回类型为“void”的 Kotlin 函数?

If Java interop is of topmost priority I would either just use the Java functional interfaces directly (ie Consumer , Supplier , etc.) or create custom Kotlin functional interfaces for now.如果 Java 互操作是最优先考虑的,我要么直接使用 Java 功能接口(即ConsumerSupplier等),要么暂时创建自定义Kotlin 功能接口 Meanwhile Kotlin handles functional interfaces better...同时 Kotlin 更好地处理功能接口......

Java variant: Java变体:

interface Foo{
  fun bar(x : java.util.function.Consumer<String>)
}
// calling this from Kotlin today looks the same as if we used (String) -> Unit:
foo.bar { println(it) }

Kotlin variant with custom Consumer :具有自定义Consumer的 Kotlin 变体:

fun interface MyConsumer<T> { // just a demo... probably depends on your needs
   fun accept(t : T)
   // other functions?
}

Usage is similar as above.用法和上面类似。 Maybe there is even an easier way today to handle something like (String) -> Unit as Consumer<String> but then I do not know it yet (or didn't feel the need to research for it yet;-)).也许今天甚至有一种更简单的方法来处理诸如(String) -> Unit as Consumer<String>之类的东西,但后来我还不知道(或者觉得还没有必要研究它;-))。 Compiler annotations as Ilya mentioned in the comments may be a way to solve this issue ~centrally. Ilya 在评论中提到的编译器注释可能是集中解决此问题的一种方法。

In Dec 2018 I wrote: I do not have a real answer to this, but I will share, what I did in such a situation where I needed to access such Kotlin code from Java (or what has come to my mind).在 2018 年 12 月,我写道:我对此没有真正的答案,但我会分享我在需要从 Java 访问此类 Kotlin 代码的情况下所做的事情(或者我想到的)。

Basically it depends which side you really want to touch/enhance just to get what you require.基本上,这取决于您真正想要触摸/增强哪一侧以获得您需要的东西。

Enhancing the Kotlin code to support the Java equivalents:增强 Kotlin 代码以支持 Java 等价物:

interface Foo {
  fun bar(x : (String) -> Unit)

  /* the following is only here for Java */
  @JvmDefault // this requires that you add -Xjvm-default=enable to your compiler flags!
  fun bar(x:Consumer<String>) = bar(x::accept)
}

This has some drawbacks: the Consumer -method is visible from Kotlin as well and is therefore also callable from there.这有一些缺点: Consumer方法在 Kotlin 中也是可见的,因此也可以从那里调用。 Needless to say, that you need to duplicate all the functions in the interfaces and therefore your whole Kotlin-interfaces just get more bloated.不用说,您需要复制接口中的所有功能,因此您的整个 Kotlin 接口只会变得更加臃肿。 But: it works from both sides the way you would expect.但是:它的工作方式与您期望的一样。 Java calls the Consumer -variant, Kotlin calls the (String) -> Unit -variant... hopefully;-) actually just demoing some calls: Java 调用Consumer -variant,Kotlin 调用(String) -> Unit -variant ...希望;-) 实际上只是演示一些调用:

// from Java:
..bar(s -> { System.out.println(s); })
// however, method references might not work that easily or not without a workaround...
..bar((Consumer<String>) System.out::println); // not nice... @JvmName("kotlinsBar") to the rescue? well... that will just get more and more ugly ;-)

// from Kotlin:
..bar(Consumer(::println)) // or: ..bar(Consumer { println(it) })
..bar(::println)           // or: ..bar { println(it) } // whatever you prefer...

That having said, another variant is to add helper methods that actually help calling the Kotlin functions easier from Java, eg something as follows:话虽如此,另一种变体是添加辅助方法,这些方法实际上有助于更轻松地从 Java 调用 Kotlin 函数,例如:

fun <T> `$`(consumer: Consumer<T>): (T) -> Unit = consumer::accept

Which will probably never be called from Kotlin (as writing the backticks combined with the $ is already cumbersome enough) or if you do not want to bloat your Kotlin code just add such a method to Java, where however it doesn't look that slim:这可能永远不会从 Kotlin 调用(因为将反引号与 $ 结合起来已经很麻烦了)或者如果你不想膨胀你的 Kotlin 代码只需将这样的方法添加到 Java,但是它看起来并不那么苗条:

static <T> Function1<T, Unit> $(Consumer<T> consumer) {
    return t -> {
        consumer.accept(t);
        return Unit.INSTANCE;
    };
}

Calls to those methods both look the same:对这些方法的调用看起来都一样:

..bar($(s -> /* do something with s */)) // where bar(x : (String) -> Unit)

For the things I needed to solve I just returned Unit.INSTANCE or null , but if I had more methods to call I would probably have chosen the second ( $(...) ) approach.对于我需要解决的问题,我只是返回Unit.INSTANCEnull ,但如果我有更多方法可以调用,我可能会选择第二种 ( $(...) ) 方法。 In the best case I only need to supply (generate? ;-)) equivalents once and use them in several projects whereas supplying default variants in the interfaces just for Java will probably require way more work and may even confuse some people...在最好的情况下,我只需要提供 (generate? ;-)) 等价物一次并在多个项目中使用它们,而在接口中为 Java 提供default变体可能需要更多的工作,甚至可能会让一些人感到困惑......

Finally: no... I don't know of any option that allows you to have something like void -functional interfaces (/consumers) out of the Unit -returning functional interfaces of Kotlin.最后:不......我不知道有什么选项可以让你从 Kotlin 的Unit返回功能接口中获得类似void功能接口(/消费者)的东西。

Actually there's no need to add the $ symbol in Roland's answer.其实罗兰的回答中不需要加$符号。
You can directly achieve good coding experience in both kotlin and in java with only one method name.只需一个方法名,就可以直接在kotlin和java中获得良好的编码体验。

Here's what you need to do (actually it's the same as Roland's answer but with my example code for you to refer to):这是您需要做的(实际上它与罗兰的答案相同,但带有我的示例代码供您参考):

  1. define an interface for java to use定义一个接口供java使用
interface `Consumer$`<T> : Function1<T, Unit> {
    fun accept(t: T)

    @JvmDefault
    override fun invoke(t: T) {
        accept(t)
    }
}
// this interface is a FunctionalInterface
// the `$` prevents importing collision with java.util.functional.Consumer
  1. in your class/interface, add a function for java to call在你的类/接口中,添加一个函数供java调用
class Foo {
    fun bar(f: (String) -> Unit) {}
    fun bar(f: `Consumer$`<String>) {
        bar(f as (String)->Unit)
                      // because that the `Consumer$` extends Function1
                      // it can be directly passed as a kotlin function
    }
}
  1. in kotlin code, you may write在科特林代码中,你可以写
foo.bar { it.xxx }
  1. in java code, you may write在java代码中,你可以写
foo.bar(it -> it.xxx)
// as well as
foo.bar(System.out::println)

The javac knows that the return type of the referencing method is not Unit , so it will call the Consumer$ method. javac 知道引用方法的返回类型不是Unit ,因此它将调用Consumer$方法。
The kotlin compiler will not check the inheritance of FunctionX , so it will call the (String)->Unit method. kotlin 编译器不会检查FunctionX的继承,因此它会调用(String)->Unit方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何为 Java 调用者声明返回类型为“void”的 Kotlin 函数? - How to declare a Kotlin function with return type 'void' for a java caller? 在Kotlin中使用Java Void类型 - Using Java Void type in Kotlin Void返回类型在Kotlin中意味着什么 - What does Void return type mean in Kotlin 如何将方法的返回类型声明为传递给方法的数组中最后一个lambda的返回类型 - How to declare method's return type the as return type of last lambda in array passed to the method 如何在Java中使用返回类型为void的递归方法? - How to use a recursive method that has a return type void in java? 如何向 Scala 提供 Java 回调(返回类型为 'void')? - How to provide Java callbacks (with 'void' return type), to Scala? Java中返回类型为void的方法中返回的意义 - Significance of return in the method with return type as void in Java 有没有一种更简单的方法可以将 lambda 声明为 java 中的变量,类似于 Kotlin? - Is there an easier way to declare a lambda as a variable in java similar to that of Kotlin? 如何使一个带有void返回类型方法且无参数的匿名类转换为lambda表达式? - How to make a anonymous class with void return type method and no parameters into a lambda expression? 如何在Java中返回void方法? - How to return void methods in Java?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM