簡體   English   中英

Scala與Java SAM互操作,沒有2.12 M2標志

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

是否有任何可接受的技術可以針對使用Java @FunctionalInterface / SAM / lambda表達式的Java-8 API編寫Scala代碼?

雖然Java lambda表達式互操作在M2 http://www.scala-lang.org/news/2.12.0-M2的標志下可用,但我更希望類型類/ AnyVal解決方案可以與scala一起使用.FunctionX特征。

不幸的是,scala.FunctionX擴展了AnyRef而不是Any,所以不能將這些特性用於/混合到隱式的AnyVal類實現中。

補充:即使scala.FunctionX是全局特征(從Any擴展),我也不確定我是如何實現目標的。 我的用例是這樣的:

在我的一個項目中,我選擇提供Java-8 API和FunctionalInterfaces,如Java Stream接口和類,以滿足最廣泛的基於JVM的客戶端語言的需求,例如Closure,Scala,Kotlin。 對於使用我的Java-8 API的每種客戶端語言,我將編寫適當的綁定(如果需要)以使用特定於語言的習語,如果訪問Java-8 API時使用該語言會感到笨拙。

順便說一句。 我也會對Kotlin-Java互操作環境中對此問題的任何評論感興趣。

這個Scala程序為我的問題展示了硬幣的一面,也就是說,如何讓Scala函數偽裝成Java 8 Lambdas。

在語法和慣用方面,通過創建一些隱式Scala函數將Scala函數轉換為Java 8 FunctionalInterface對應類型,似乎可以正常工作。

當然,需要注意的是,這種方法沒有利用Java 8通過invokedynamic優化lambda創建的能力。

因此,這種方法導致為Scala函數實例創建JVM對象,與Java 8本機lambda相比,這可能會影響內存使用和性能。

對於硬幣的另一面,也就是說,如何讓Java 8 Lambdas偽裝成Scala函數,我想有人必須編寫一些Java代碼來與Scala互操作(如果一個人的目標是擁有一個可調用的Scala API)來自Java)。

Justin Johansson,關於我的項目發條的微博,JVM上的XPath / XQuery的新實現,在Twitter上的@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
*/

順便說一句。 我也會對Kotlin-Java互操作環境中對此問題的任何評論感興趣。

Kotlin的FunctionX接口是SAM的,所以沒有必要做任何額外的事情來讓Java 8理解它們

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM