簡體   English   中英

從Scala 2.13方法向Java 8調用者返回類型化的集合

[英]Returning typed collection from Scala 2.13 method to Java 8 caller

我想將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);
    }
}

問題是類型擦除java.util.List[scala.Int]轉換為java.util.List<java.lang.Object> 例如, intoEvenOddForJava javap輸出為

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

然后在FunctionConverterFromJava.intoEvenOddForJava調用intoEvenOddAsJava.asJava

隱藏在庫中的asInstanceOf可能是可以接受的, 因為

... Int的基本表示形式是Integer您可以直接將其java.util.List[java.lang.Integer]java.util.List[java.lang.Integer]


在發表評論時,尤金的答案解釋了

...如果刪除泛型,它如何得知Integer(通過checkcast )? 答案是在編譯A或您的情況下生成的可選Signature

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

Signature信息是編譯器用來通過運行時檢查在調用站點上強制類型安全的信息; 如果該字段不存在-那將是不可能的。

暫無
暫無

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

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