将类型化的集合从Scala 2.13方法返回给Java 8调用者

时间:2019-07-17 19:30:33

标签: java scala function scala-java-interop

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

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);
    }
}

1 个答案:

答案 0 :(得分:3)

问题是type erasurejava.util.List[scala.Int]变成java.util.List<java.lang.Object>。例如,javap的{​​{1}}输出是

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

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

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.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.asJava

隐藏在库中的FunctionConverterFromJava.intoEvenOddForJava是可以接受的because

  

... asInstanceOf的基础表示形式是Int,您可以进行强制转换   直接到Integer


发表评论,尤金(Eugene)的回答explains

  

...它怎么知道   关于整数(通过泛型java.util.List[java.lang.Integer])是否已删除?答案   是在编译A或在A中生成的可选checkcast   您的案例:

     

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

     

()Lscala/collection/immutable/List<Ljava/lang/Integer;>; // fooInteger信息是编译器用来强制执行的信息   通过运行时检查在呼叫站点输入安全性;如果该字段不   在场-那是不可能的。