2

我想用 Java 表达以下所有 Scala 代码:

object TupleDemo {
  val tuple = (3, "Hello, world! ")

  /** @return str replicated x times */
  def foo(x: Int, str: String) = str * x

  val tupledFoo1 = (foo _).tupled // partially applied function

  val tupledFoo2 = Function.tupled(foo _) // desugared syntax for same partially applied function
}

object TupleDemoApp extends App {
  import TupleDemo._

  println(tupledFoo1(tuple)) // Hello, world! Hello, world! Hello, world!
  println(tupledFoo2(tuple)) // Hello, world! Hello, world! Hello, world!
}

这是我能想到的 Java 等价物:

import scala.Function1;
import scala.Function2;
import scala.Tuple2;
import scala.collection.immutable.WrappedString;
import scala.runtime.AbstractFunction2;

public class JavaTupleDemo {
   /** @return str replicated x times */
   static final Function2<Integer, String, String> foo = new AbstractFunction2<Integer, String, String>() {
       public String apply(Integer x, String str) {
           return new WrappedString(str).$times(x);
       }

       // perhaps the types for this method are incorrect?
       public Function1<Tuple2<Integer, String>, String> tupled(Tuple2 tuple2) {
           return null; // what to write here instead of null?
       }
   };

  public static void main(String[] args) {
      // works: Invoke tupled function defined in Scala from Java using Tuple2 defined in Java
      Tuple2<Object, String> tuple = new Tuple2<Object, String>(3, "Hello, World! ");
      System.out.println(TupleDemo.tupledFoo1().apply(tuple));

      // works: Invoke regular function defined in Java from Java
      System.out.println(JavaTupleDemo.foo.apply(3, "Hello, planet! "));

      // stumped: Invoke tupled function defined in Java from Java using both the Scala and the Java Tuple2 instances
  }
}
4

2 回答 2

4

tupled是在Function2(因此也是AbstractFunction2)中实现的,所以这里不需要定义它——你可以这样写:

import scala.Function;
import scala.Function2;
import scala.Tuple2;
import scala.collection.immutable.WrappedString;
import scala.runtime.AbstractFunction2;

public class JavaTupleDemo {
  static final Function2<Integer, String, String> foo =
    new AbstractFunction2<Integer, String, String>() {
      public String apply(Integer x, String str) {
        return new WrappedString(str).$times(x);
      }
    };

  public static void main(String[] args) {
    Tuple2<Integer, String> tuple =
      new Tuple2<Integer, String>(3, "Hello, World! ");

    System.out.println(JavaTupleDemo.foo.tupled().apply(tuple));
    System.out.println(Function.tupled(JavaTupleDemo.foo).apply(tuple));
  }
}

请注意,我们需要编写foo.tupled(),因为 Java 将其视为一种方法,并且在这两种情况下我们都会得到 a Function1,所以我们必须编写.apply(tuple),否则这与 Scala 版本基本相同。


为了解决您关于将Integer元组中的Object:Integer

Tuple2<Object, String> scalaTuple = TupleDemo.tuple();

Tuple2<Integer, String> tuple = new Tuple2<Integer, String>(
  (Integer) scalaTuple._1(),
  scalaTuple._2()
);

即,只需将元组拆开,投射Integer,然后将其重新组合在一起。

于 2012-12-22T02:51:59.783 回答
0

Travis Brown 的答案的问题在于他没有包含所有代码。这是完整的代码,无法编译。

import scala.Function;
import scala.Function2;
import scala.Tuple2;
import scala.collection.immutable.WrappedString;
import scala.runtime.AbstractFunction2;

public class JavaTupleDemo {
   /** tupled() is implemented in Function2 (and therefore in AbstractFunction2)
    * @return str replicated x times */
   static final Function2<Integer, String, String> foo = new AbstractFunction2<Integer, String, String>() {
       public String apply(Integer x, String str) {
           return new WrappedString(str).$times(x);
       }
   };

  public static void main(String[] args) {
      // Invoke tupled function defined in Scala from Java using Tuple2 defined in Java
      Tuple2<Object, String> tuple = new Tuple2<Object, String>(3, "Hello, World! ");
      System.out.println(TupleDemo.tupledFoo1().apply(tuple));

      // Invoke regular function defined in Java from Java
      System.out.println(JavaTupleDemo.foo.apply(3, "Hello, planet! "));

      // Invoke tupled function defined in Java from Java using both the Scala and the Java Tuple2 instances
      System.out.println(JavaTupleDemo.foo.tupled().apply(tuple));
      System.out.println(Function.tupled(JavaTupleDemo.foo).apply(tuple));
  }
}

错误消息是:

error: method apply in interface Function1<T1,R> cannot be applied to given types;
required: Tuple2<Integer,String>
found: Tuple2<Object,String>
reason: actual argument Tuple2<Object,String> cannot be converted to Tuple2<Integer,String> by method invocation conversion
where T1,R are type-variables:
T1 extends Object declared in interface Function1
R extends Object declared in interface Function1

您不能简单地将元组转换为 Tuple2<Integer, String>。如果您尝试以下操作:

System.out.println(JavaTupleDemo.foo.tupled().apply((Tuple2<Integer, String>)tuple));
System.out.println(Function.tupled(JavaTupleDemo.foo).apply((Tuple2<Integer, String>)tuple));

错误信息是:

error: inconvertible types
required: Tuple2<Integer,String>
found:    Tuple2<Object,String>

进行此编译的唯一方法是做一些非常讨厌的事情 - 首先将元组转换为 Object,然后转换为 Tuple2<Integer, String>:

System.out.println(JavaTupleDemo.foo.tupled().apply((Tuple2<Integer, String>)((Object)javaTuple)));
System.out.println(Function.tupled(JavaTupleDemo.foo).apply((Tuple2<Integer, String>)((Object)javaTuple)));

有一个更好的方法吗?

于 2012-12-22T21:13:28.513 回答