2012-12-21 34 views
1

我想表達以下所有Scala代碼的Java中:調用scala.Function.tupled()從Java

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

回答

3

tupledFunction2實現的(因此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認爲這是一種方法,並且在這兩種情況下我們都得到一個Function1,所以我們必須編寫.apply(tuple),否則這基本上與Scala版本相同。


爲了解決有關獲取的類型爲Object元組中的Integer你的問題:處理這個最簡單的方法(假設你不能或不想使它成爲Integer明確的斯卡拉側)可能是以下幾點:

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

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

也就是說,只取元組分開,鑄就Integer,並把它重新走到一起。

+0

我非常親密,但不能完全到達那裏。謝謝! –

+0

元組的Scala版本對於Java而言表現爲Tuple2 ,但元組的Java版本必須是Tuple2 。不可能從一個轉換到另一個,所以我不能將代碼的最後兩行插入我的代碼中。 –

0

特拉維斯布朗回答的問題是,他沒有包括所有的代碼。這是完整的代碼,它不會編譯。

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 <整數,字符串>。如果您嘗試以下方法:

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> 

,使這個編譯唯一的辦法就是做真正討厭的事情 - 第一投的元組對象,然後到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))); 

有沒有更好的方法來做到這一點?