java - 将类型化集合从 Scala 2.13 方法返回到 Java 8 调用者

标签 java scala function scala-java-interop

我要回java.util.List<Integer>改为下面的 Java 8 代码,而不是 java.util.List<Object>从以下 Scala 2.13.0 代码返回。 Java 和 Scala 代码都可以修改以适应需要。我不想强制任何类型转换,例如 no (java.util.List<Integer>).asInstanceOf[java.util.List[Int]] Actor 阵容。

<强> collections.FunctionConverterFromJava.scala

trait FunctionConverterFromScala {
  import java.util.{List => JList}
  import scala.collection._

  val intoEvenOdd: JList[Int] => (JList[Int], JList[Int]) = {
    import scala.jdk.CollectionConverters._
    javaList: JList[Int] =>
      javaList.asScala.partition(_ % 2 == 0) match {
      case (even: mutable.Buffer[Int], odd: mutable.Buffer[Int]) =>
        (even.asJava, odd.asJava)
    }
  }
}

object FunctionConverterFromJava extends FunctionConverterFromScala {
  import java.util.{function, List => JList}

  def reverse(string: String): String = string.reverse

  def zipChars(string: String): IndexedSeq[(Char, Int)] = string.zipWithIndex

  val intoEvenOddForJava: function.Function[JList[Int], (JList[Int], JList[Int])] = {
    import scala.jdk.FunctionConverters._
    intoEvenOdd.asJava
  }
}

object FunctionConverterFun extends App with FunctionConverterFromScala {
  val jList: java.util.List[Int] = {
    import scala.jdk.CollectionConverters._
    (1 to 10).asJava
  }
  println(intoEvenOdd(jList))
}

Java程序

import collections.FunctionConverterFromJava$;
import scala.Tuple2;
import scala.collection.immutable.IndexedSeq;
import java.util.Arrays;
import java.util.List;

public class FunctionConverterFun {
    public static void main(String[] args) {
        String string = "Hello!";
        String reversed = FunctionConverterFromJava$.MODULE$.reverse(string);
        System.out.println("reversed = " + reversed);

        IndexedSeq<Tuple2<Object, Object>> zippedChars = FunctionConverterFromJava$.MODULE$.zipChars(string);
        System.out.println("zippedChars = " + zippedChars);

        List<Object> list1 = Arrays.asList(1, 2);
        Tuple2<List<Object>, List<Object>> list2 = FunctionConverterFromJava$.MODULE$.intoEvenOddForJava().apply(list1);
        System.out.println("list2 = " + list2);

        java.util.function.Function<List<Object>, Tuple2<List<Object>, List<Object>>> f = FunctionConverterFromJava$.MODULE$.intoEvenOddForJava();
        Tuple2<List<Object>, List<Object>> list3 = f.apply(list1);
        System.out.println("list3 = " + list3);
    }
}

最佳答案

问题是type erasurejava.util.List[scala.Int]进入java.util.List<java.lang.Object> 。例如,javap输出 intoEvenOddForJava

public scala.Function1<java.util.List<java.lang.Object>, scala.Tuple2<java.util.List<java.lang.Object>, java.util.List<java.lang.Object>>> intoEvenOddForJava();

但是,如果我们从 scala.Int 更改至java.lang.Integer像这样

object FunctionConverterFromJava extends FunctionConverterFromScala {
  ...
  val intoEvenOddForJava: function.Function[JList[java.lang.Integer], (JList[java.lang.Integer], JList[java.lang.Integer])] = {
    intoEvenOdd.asJava.asInstanceOf[function.Function[JList[java.lang.Integer], (JList[java.lang.Integer], JList[java.lang.Integer])]]
  }
}

然后我们根据 javap 避免类型删除输出

public java.util.function.Function<java.util.List<java.lang.Integer>, scala.Tuple2<java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>>> intoEvenOddForJava();

现在我们可以根据需要从 Java 调用

java.util.function.Function<List<Integer>, Tuple2<List<Integer>, List<Integer>>> f = FunctionConverterFromJava$.MODULE$.intoEvenOddForJava();
Tuple2<List<Integer>, List<Integer>> list3 = f.apply(list1);
System.out.println("list3 = " + list3);

输出

list3 = ([2],[1])

现在我明白您希望避免 asInstanceOf ,但请注意它将隐藏在库中 FunctionConverterFromJava ,也就是说,调用站点将清除 asInstanceOf 。如果您仍然希望避免 asInstanceOf完全,然后考虑将以下内容添加到 FunctionConverterFromScala

val intoEvenOddAsJava: JList[java.lang.Integer] => (JList[java.lang.Integer], JList[java.lang.Integer]) = {
  import scala.jdk.CollectionConverters._
  javaList: JList[java.lang.Integer] =>
    javaList.asScala.partition(_ % 2 == 0) match {
      case (even: mutable.Buffer[java.lang.Integer], odd: mutable.Buffer[java.lang.Integer]) =>
        (even.asJava, odd.asJava)
    }
}

然后调用intoEvenOddAsJava.asJavaFunctionConverterFromJava.intoEvenOddForJava .

那个asInstanceOf隐藏在库中可能是可以接受的because

...the underlying representation of Int is Integer you can cast directly to java.util.List[java.lang.Integer]


针对评论,尤金的回答 explains

...how does it know about Integer (via that checkcast) if generics are erased? The answer is the optional Signature that is generated when A is compiled, or in your cases:

()Lscala/collection/immutable/List<Ljava/lang/Object;>; //fooInt ()Lscala/collection/immutable/List<Ljava/lang/Integer;>; // fooInteger

This Signature information is what is used by the compiler to enforce type safety at callsites, via runtime checks; if this field would not be present - that would have been impossible.

关于java - 将类型化集合从 Scala 2.13 方法返回到 Java 8 调用者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57082946/

相关文章:

Java模式以保持集合中数据索引的一致性

java - 混合 java/scala 项目的自动生成文档

scala - 如何为我的 Scala 类定义强制转换和隐式强制转换操作?

regex - Spark 2.2/Jupyter Notebook SQL regexp_extract 函数与正则表达式模式不匹配

c++ - Visual Studio 2013 c++ 函数语法错误

java - 进度条仅在 Debug模式下显示。作业加异步显示

java - 解析 URL 以获取 hyber 链接并将 hyber 链接存储在单独的变量中

c++ - 从函数返回期间复制构造函数的目的是什么?

c - 这个数组函数有什么作用呢? - C 编程

java - Promise 返回 play.libs.F$Promise@65722df2 而不是字符串值