如何在Scala中使用Java lambdas

zer*_*ing 7 java lambda scala scala-java-interop

我有以下代码:

source
    .mapValues(value -> value + " Stream it!!!")
    .print(Printed.toSysOut());
Run Code Online (Sandbox Code Playgroud)

如您所见,mapValues需要一个lambda表达式.

现在,我正在使用Java库,但应用程序是用Scala编写的.如何将Scala lambda传递给Java代码?

我尝试了以下方法:

source
  .mapValues(value => value + "hello")
  .print(Printed.toSysOut)
Run Code Online (Sandbox Code Playgroud)

但编译器抱怨:

[error]   (x$1: org.apache.kafka.streams.kstream.Printed[String,?0(in value x$1)])Unit <and>
[error]   (x$1: org.apache.kafka.streams.kstream.KeyValueMapper[_ >: String, _ >: ?0(in value x$1), String])Unit <and>
[error]   (x$1: String)Unit
[error]  cannot be applied to (org.apache.kafka.streams.kstream.Printed[Nothing,Nothing])
[error]       .print(Printed.toSysOut)
[error]        ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 2 s, completed Nov 19, 2017 7:53:44 PM
Run Code Online (Sandbox Code Playgroud)

Dmy*_*tin 12

这取决于您的Scala版本.

在2.12中,Scala函数可用于需要Java函数的地方,反之亦然.

App1.java

import java.util.function.Function;

public class App1 {
    public static void method(Function<String, String> function) {
        System.out.println(function.apply("a"));
    }

    public static void main(String[] args) {
        App.method1((String s) -> s.toUpperCase());
    }
}
Run Code Online (Sandbox Code Playgroud)

App.scala

object App {
  def main(args: Array[String]): Unit = {
    App1.method((s: String) => s.toUpperCase)
  }

  def method1(function: String => String): Unit = {
    println(function("xyz"))
  }
}
Run Code Online (Sandbox Code Playgroud)

在2.11你可以使用 scala-java8-compat

libraryDependencies += "org.scala-lang.modules" %% "scala-java8-compat" % "0.8.0"
Run Code Online (Sandbox Code Playgroud)

App1.java

import java.util.function.Function;
import static scala.compat.java8.JFunction.func;

public class App1 {
    public static void method(Function<String, String> function) {
        System.out.println(function.apply("a"));
    }

    public static void main(String[] args) {
        App.method1(func((String s) -> s.toUpperCase()));
    }
}
Run Code Online (Sandbox Code Playgroud)

App.scala

import scala.compat.java8.FunctionConverters._

object App {
  def main(args: Array[String]): Unit = {
    App1.method(((s: String) => s.toUpperCase).asJava)
  }

  def method1(function: String => String): Unit = {
    println(function("xyz"))
  }
}
Run Code Online (Sandbox Code Playgroud)

或者在Scala中的2.11中,您可以在和之间定义隐式转换器.java.util.function.Functionscala.Function1

所以如果你使用2.11试试

source
  .mapValues((value => value + "hello").asJava)
  .print(Printed.toSysOut) 
Run Code Online (Sandbox Code Playgroud)

要么

source
  .mapValues(((value: String) => value + "hello").asJava)
  .print(Printed.toSysOut[String, String])
Run Code Online (Sandbox Code Playgroud)


Ric*_*rty 5

错误消息列出了print支持的参数类型.其中之一是:

org.apache.kafka.streams.kstream.Printed[String,?0(in value x$1)]
Run Code Online (Sandbox Code Playgroud)

从错误消息中您可以看到您提供Printed.toSysOut的类型:

org.apache.kafka.streams.kstream.Printed[Nothing,Nothing]
Run Code Online (Sandbox Code Playgroud)

根据Kafka 1 javadoc(PrintedKafka 1.1中没有),toSysOut定义为:

public static <K,V> Printed<K,V> toSysOut()
Run Code Online (Sandbox Code Playgroud)

所以答案问题是Scala是推断KV类型的Nothing.您需要明确提供类型.

以下可能会奏效:

source
  .mapValues[String](value -> value + " Stream it!!!")
  .print(Printed.toSysOut[String,String])
Run Code Online (Sandbox Code Playgroud)