2011-07-01 3 views
41

पर विचार करें निम्नलिखित स्काला कोड:जावा से स्काला का उपयोग करना: कार्यों गुजर के रूप में मानकों

package scala_java; 
public class MyJava { 
    public static void main(String [] args) { 
     MyScala.setFunc(myFunc); // This line gives an error 
    } 
    public static String myFunc(int someInt) { 
     return String.valueOf(someInt); 
    } 
} 

हालांकि, इसके बाद के संस्करण है: जावा में अब

package scala_java 
object MyScala { 
    def setFunc(func: Int => String) { 
    func(10) 
    } 
} 

, मैं के रूप में MyScala उपयोग करने के लिए इसे पसंद किया है | काम नहीं करते (जैसा कि जावा से कार्यात्मक प्रोग्रामिंग की अनुमति नहीं है)। जावा में फ़ंक्शन को पास करने का सबसे आसान कामकाज क्या है? मुझे एक सामान्य समाधान चाहिए जो पैरामीटर के मनमाना संख्या वाले कार्यों के साथ काम करता है।

संपादित करें: क्या जावा 8 के नीचे चर्चा की गई क्लासिक समाधानों की तुलना में कोई बेहतर वाक्यविन्यास है?

उत्तर

25

आपको जावा में Function1 मैन्युअल रूप से तुरंत चालू करना होगा। कुछ ऐसा:

final Function1<Integer, String> f = new Function1<Integer, String>() { 
    public int $tag() { 
     return Function1$class.$tag(this); 
    } 

    public <A> Function1<A, String> compose(Function1<A, Integer> f) { 
     return Function1$class.compose(this, f); 
    } 

    public String apply(Integer someInt) { 
     return myFunc(someInt); 
    } 
}; 
MyScala.setFunc(f); 

यह Daniel Spiewak’s “Interop Between Java and Scala” article से लिया गया है।

+4

टिप्पणियों में लेख और डैनियल की 'FunUtils' कक्षा को देखना सुनिश्चित करें, जो '$ टैग' और 'compose' के लिए आवश्यक बॉयलरप्लेट को हटाने में मदद करता है। –

+0

यह बहुत जानकारीपूर्ण है। मैंने पहले लेख देखा था लेकिन टिप्पणियां नहीं पढ़ीं। – Jus12

7

मेरे लिए सबसे आसान तरीका है परिभाषित एक जावा इंटरफ़ेस की तरह:

public interface JFunction<A,B> { 
    public B compute(A a); 
} 

फिर अपने स्केला कोड, setFunc ओवरलोडिंग जैसे भी JFunction वस्तुओं स्वीकार करने के लिए संशोधित:

object MyScala { 
    // API for scala 
    def setFunc(func: Int => String) { 
    func(10) 
    } 
    // API for java 
    def setFunc(jFunc: JFunction[Int,String]) { 
    setFunc((i:Int) => jFunc.compute(i)) 
    } 
} 

आप स्वाभाविक रूप से स्कैला से पहली परिभाषा का उपयोग करेंगे, लेकिन फिर भी जावा से दूसरे का उपयोग करने में सक्षम होंगे:

public class MyJava { 
    public static void main(String [] args) { 
    MyScala.setFunc(myFunc); // This line gives an error 
    } 

    public static final JFunction<Integer,String> myFunc = 
    new JFunction<Integer,String>() { 
     public String compute(Integer a) { 
     return String.valueOf(a); 
     } 
    }; 

} 
+0

@ जुस 12। धन्यवाद, यह तय है। – paradigmatic

+0

असल में, स्कैला के कार्यों * पहले से ही * दृश्यों के पीछे एक एसएएम प्रकार के रूप में लागू किए गए हैं। इसलिए आप सीधे 'फंक्शन एन' (जीन-फिलिप के उत्तर के अनुसार) को कार्यान्वित कर सकते हैं और अपने स्वयं के 'JFunction' प्रकार को पेश करने की आवश्यकता नहीं है। –

+0

मैं असहमत हूं, जबकि आप सीधे जावा से स्कैला फ़ंक्शन को तुरंत चालू कर सकते हैं, परिणामी कोड बदसूरत है। यदि आप कभी-कभी कुछ स्कैला कोड तक पहुंचना चाहते हैं, तो यह ठीक है। लेकिन यदि आप जावा एपीआई प्रदान करते हैं, तो जावा एपीआई के लिए डिज़ाइन किए गए कुछ उच्च स्तरीय इंटरफ़ेस और स्कैला विधियों को जोड़कर आपके पास एक अच्छा कोड होगा। उदाहरण के लिए निहित प्रस्तावों की कमी से निपटने में बहुत मदद मिलेगी। – paradigmatic

58

scala.runtime पैकेज में, AbstractFunction1 नामक अमूर्त वर्ग हैं और इसी तरह अन्य धर्मार्थियों के लिए भी हैं। उन्हें जावा से उपयोग करने के लिए आप केवल, apply ओवरराइड करने के लिए इस तरह की जरूरत है:

Function1<Integer, String> f = new AbstractFunction1<Integer, String>() { 
    public String apply(Integer someInt) { 
     return myFunc(someInt); 
    } 
}; 

आप जावा 8 पर हैं और इस बात के लिए जावा 8 लैम्ब्डा सिंटैक्स का उपयोग करने, https://github.com/scala/scala-java8-compat की जाँच करें।

+2

धन्यवाद! आपका जवाब सभी का सबसे सहायक है! फंक्शन 1 को लागू करने का प्रयास करते हुए, जावा मुझे बताता है कि मुझे दर्जनों तरीकों को लागू करना है - फंक्शन 1 में कई आदिम प्रकारों के लिए विशेषज्ञता है। –

+1

यह * वह उत्तर है जिसे आप ढूंढ रहे हैं :) यह भी देखें http://twitter.github.io/scala_school/java.html – alexr

+0

ध्यान दें कि यदि आप एंड्रॉइड या आईओएस के लिए संकलित कर रहे हैं, तो आप सक्षम नहीं होंगे scala-java8-compat का उपयोग करने के लिए क्योंकि retrolambda केवल उसमें संशोधित कर सकता है जिसके लिए आपके पास स्रोत फ़ाइलें हैं। न ही स्रोत में लैम्ब्डा ब्रिज क्लासेस (JFunction0 इत्यादि) हैं क्योंकि वे एसबीटी से सीधे क्लाउड से जेनरेट किए गए कोड हैं। संभवतः आपके प्रोजेक्ट में .class फ़ाइलों को शामिल करने का एक तरीका है जहां रेट्रोलंबडा उन्हें संशोधित कर सकता है, लेकिन मैंने इसे समझने के प्रयास को निवेश नहीं किया है। – voxoid

0

यहाँ एक समाधान पर मेरे प्रयास, एक छोटे से पुस्तकालय है: https://github.com/eirslett/sc8

आप एफ (...) में अपने जावा 8 लैम्ब्डा लपेट और फिर इसे एक स्काला समारोह में बदला न गया।