简体   繁体   English

Scala与Java SAM互操作,没有2.12 M2标志

[英]Scala interop with Java SAM without 2.12 M2 flag

Is there any accepted technique of writing Scala code against a Java-8 API which uses Java @FunctionalInterface / SAM / lambda expressions? 是否有任何可接受的技术可以针对使用Java @FunctionalInterface / SAM / lambda表达式的Java-8 API编写Scala代码?

While Java lambda expressions inter-op is available under a flag in M2 http://www.scala-lang.org/news/2.12.0-M2 , I was rather hoping that a type class / AnyVal solution might work together with scala.FunctionX traits. 虽然Java lambda表达式互操作在M2 http://www.scala-lang.org/news/2.12.0-M2的标志下可用,但我更希望类型类/ AnyVal解决方案可以与scala一起使用.FunctionX特征。

Unfortunately though, scala.FunctionX extends AnyRef and not Any so one cannot use/mix these traits into an implicit AnyVal class implementation. 不幸的是,scala.FunctionX扩展了AnyRef而不是Any,所以不能将这些特性用于/混合到隐式的AnyVal类实现中。

Added: I'm not entirely sure that I though out how I would achieve my aim even if scala.FunctionX were global traits (extending from Any). 补充:即使scala.FunctionX是全局特征(从Any扩展),我也不确定我是如何实现目标的。 My use case is this though: 我的用例是这样的:

In a project of mine, I've chosen to provide a Java-8 API with FunctionalInterfaces like the Java Stream interfaces & classes so as to cater for the widest possible audience of JVM-based client languages eg Closure, Scala, Kotlin. 在我的一个项目中,我选择提供Java-8 API和FunctionalInterfaces,如Java Stream接口和类,以满足最广泛的基于JVM的客户端语言的需求,例如Closure,Scala,Kotlin。 For each client language using my Java-8 API, I will write appropriate bindings (if necessary) to use language-specific idioms if in event of accessing Java-8 API feels clunky in that language. 对于使用我的Java-8 API的每种客户端语言,我将编写适当的绑定(如果需要)以使用特定于语言的习语,如果访问Java-8 API时使用该语言会感到笨拙。

btw. 顺便说一句。 I would be interested in any comments with this question taken in a Kotlin-Java interop context also. 我也会对Kotlin-Java互操作环境中对此问题的任何评论感兴趣。

This Scala program demonstrates one side of the coin for my question, that is, how to get Scala functions to masquerade as Java 8 Lambdas. 这个Scala程序为我的问题展示了硬币的一面,也就是说,如何让Scala函数伪装成Java 8 Lambdas。

Syntactically and idiomatically this seems to work fine by creating some implicit Scala functions to convert Scala functions to their Java 8 FunctionalInterface counterpart types. 在语法和惯用方面,通过创建一些隐式Scala函数将Scala函数转换为Java 8 FunctionalInterface对应类型,似乎可以正常工作。

The caveat is, of course, that this method does not take advantage of Java 8's ability to optimize lambda creation via invokedynamic. 当然,需要注意的是,这种方法没有利用Java 8通过invokedynamic优化lambda创建的能力。

Accordingly this approach results in a JVM object being created for the Scala function instance and this may impact upon memory usage and performance compared with Java 8 native lambdas. 因此,这种方法导致为Scala函数实例创建JVM对象,与Java 8本机lambda相比,这可能会影响内存使用和性能。

For the flip side of the coin, that is, how to get Java 8 Lambdas to masquerade as Scala functions, I guess one would have to write some Java code to interop with Scala (if one's aim was to have a Scala API that was callable from Java). 对于硬币的另一面,也就是说,如何让Java 8 Lambdas伪装成Scala函数,我想有人必须编写一些Java代码来与Scala互操作(如果一个人的目标是拥有一个可调用的Scala API)来自Java)。

Justin Johansson, Microblogging about my Project Clockwork, A new implementation of XPath/XQuery on the JVM, as @MartianOdyssey on Twitter Justin Johansson,关于我的项目发条的微博,JVM上的XPath / XQuery的新实现,在Twitter上的@MartianOdyssey

https://twitter.com/MartianOdyssey https://twitter.com/MartianOdyssey

/**
  * Scala Functions masquerading as Java 8 Lambdas.
  *
  * (C) Justin Johansson 2015.
  *
  * Microblogging about my Project Clockwork, a
  * new implementation of XPath/XQuery on the JVM,
  * as @MartianOdyssey on Twitter (https://twitter.com/MartianOdyssey).
  *
  * Permission to use this code is granted under Apache License,
  * Version 2.0 and providing attribution is afforded to author,
  * Justin Johansson.
  */

package lab

import scala.language.implicitConversions

import java.util.{ Arrays => JArrays, List => JList }
import java.util.function.{ Consumer => JConsumer, Function => JFunction, Predicate => JPredicate }
import java.util.stream.{ Stream => JStream }

object JLambda extends App {
  println("JLambda: Scala to Java 8 lambda test")

  implicit def func1ToJConsumer[T](func: T => Unit): JConsumer[T] = {
    new JConsumer[T] {
      def accept(arg: T): Unit = func(arg)
    }
  }

  implicit def func1ToJFunction[T, R](func: T => R): JFunction[T, R] = {
    new JFunction[T, R] {
      def apply(arg: T): R = func(arg)
    }
  }

  implicit def func1ToJPredicate[T](func: T => Boolean): JPredicate[T] = {
    new JPredicate[T] {
      def test(arg: T): Boolean = func(arg)
    }
  }

  val myList = JArrays.asList("cake", "banana", "apple", "coffee")
  println(s"myList = $myList")

  val myListFiltered: JStream[String] = myList.stream
    .filter { x: String => x.startsWith("c") }

  val myListFilteredAndMapped: JStream[String] = myListFiltered
    .map { x: String => x.toUpperCase }

  myListFilteredAndMapped.forEach { x: String => println(s"x=$x") }
}


/*
Outputs:
JLambda: Scala to Java 8 lambda test
myList = [cake, banana, apple, coffee]
x=CAKE
x=COFFEE
*/

btw. 顺便说一句。 I would be interested in any comments with this question taken in a Kotlin-Java interop context also. 我也会对Kotlin-Java互操作环境中对此问题的任何评论感兴趣。

Kotlin's FunctionX interfaces are SAM's, so there's no need to do anything extra to make Java 8 understand them Kotlin的FunctionX接口是SAM的,所以没有必要做任何额外的事情来让Java 8理解它们

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM