2012-11-28 11 views
217

जावा 8 में, विधियों को लैम्ब्डा अभिव्यक्ति के रूप में बनाया जा सकता है और संदर्भ द्वारा पारित किया जा सकता है (हुड के नीचे एक छोटे से काम के साथ)। लैम्बास के साथ ऑनलाइन कई उदाहरण हैं और विधियों के साथ उपयोग किए जाते हैं, लेकिन पैरामीटर के रूप में लैम्ब्डा लेने के तरीके को बनाने के तरीके के बारे में कोई उदाहरण नहीं है। इसके लिए वाक्यविन्यास क्या है?मैं एक विधि को कैसे परिभाषित करता हूं जो जावा 8 में पैरामीटर के रूप में लैम्ब्डा लेता है?

MyClass.method((a, b) -> a+b); 


class MyClass{ 
    //How do I define this method? 
    static int method(Lambda l){ 
    return l(5, 10); 
    } 
} 
+15

अच्छा प्रश्न है। और आप सही हैं: ट्यूटोरियल में से कोई भी उस भाग में शामिल नहीं है। – Martin

उत्तर

157

lambdas विशुद्ध रूप से एक कॉल-साइट निर्माण कर रहे हैं: लैम्ब्डा के प्राप्तकर्ता पता है कि एक लैम्ब्डा शामिल है की जरूरत नहीं है, बजाय यह उचित विधि के साथ एक अंतरफलक स्वीकार करता है।

दूसरे शब्दों में, आप एक कार्यात्मक इंटरफ़ेस को परिभाषित या उपयोग करते हैं (यानी एक विधि के साथ एक इंटरफ़ेस) जो स्वीकार करता है और जो भी आप चाहते हैं उसे वापस देता है।

इस जावा 8 के लिए java.util.function में आमतौर पर उपयोग किए जाने वाले इंटरफ़ेस प्रकारों के सेट के साथ आता है (जावाडोक के संकेत के लिए Maurice Naftalin पर धन्यवाद)।

इस विशिष्ट उपयोग के लिए वहाँ a single int applyAsInt(int left, int right) method साथ java.util.function.IntBinaryOperator है, तो आप इस तरह अपने method लिख सकते हैं:

static int method(IntBinaryOperator op){ 
    return op.applyAsInt(5, 10); 
} 

लेकिन तुम बस के रूप में अच्छी तरह से अपने स्वयं के इंटरफेस को परिभाषित करने और इस तरह इसका इस्तेमाल कर सकते हैं:

public interface TwoArgIntOperator { 
    public int op(int a, int b); 
} 

//elsewhere: 
static int method(TwoArgIntOperator operator) { 
    return operator.op(5, 10); 
} 

अपने स्वयं के इंटरफ़ेस का उपयोग करने का लाभ यह है कि आपके पास ऐसे नाम हो सकते हैं जो अधिक स्पष्ट रूप से इरादे को इंगित करते हैं।

+2

वहाँ में निर्मित करेंगे जा इंटरफेस प्रयोग की जाने वाली, या मैं हर लैम्ब्डा मैं ले जाना चाहते हैं के लिए एक इंटरफेस बनाने चाहिए? – Marius

+0

पुनर्प्रयोग बनाम विवरणात्मक नाम दुविधा के लिए एक अच्छा समझौता विधि यह निर्दिष्ट करता है अधिभावी बिना इंटरफ़ेस में बनाया विस्तार करने के लिए किया जाएगा। यह आपको कोड की केवल एक अतिरिक्त पंक्ति के साथ अपना वर्णनात्मक नाम देता है। –

+0

मुझे यह नहीं मिला। वह किसी भी चीज़ के लिए लैम्ब्डा पास कर सकता है और यह काम करेगा? क्या होता है यदि वह 'TwoArgIntOperator' के लिए' (int a, int b, int c) 'पास करता है। क्या होता है यदि 'TwoArgIntOperator' में एक ही हस्ताक्षर के साथ ** दो ** विधियां हैं। यह जवाब उलझन में है। –

12

http://lambdafaq.org/lambda-resources से जुड़े लैम्बडा-सक्षम जावा 8 जावाडॉक्स का सार्वजनिक वेब-सुलभ संस्करण है। (यह स्पष्ट रूप से जोआचिम सॉर के जवाब पर एक टिप्पणी होनी चाहिए, लेकिन मैं अपने एसओ खाते में उन प्रतिष्ठा बिंदुओं के साथ नहीं जा सकता जो मुझे एक टिप्पणी जोड़ने की ज़रूरत है।) Lambdafaq साइट (मैं इसे बनाए रखता हूं) इसका उत्तर देता हूं और कई अन्य जावा -लैम्ब्डा प्रश्न।

+2

लिंक और तथ्य यह है कि आप उस साइट को बनाए रखने के लिए धन्यवाद! मैंने आपके सार्वजनिक जावाडॉक के लिंक को मेरे उत्तर में जोड़ने की स्वतंत्रता ली। –

+1

एक साइड नोट के रूप में: ऐसा लगता है कि आप लैम्ब्डास के लिए निर्माण कर रहे हैं जो एंजेलिका लैंगर [जेनेरिक के लिए बनाया गया है] (http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html)। इसके लिए धन्यवाद, जावा को ऐसे संसाधनों की आवश्यकता है! –

39

लैम्ब्डा अभिव्यक्ति का उपयोग करने के लिए आपको या तो अपना स्वयं का कार्यात्मक इंटरफ़ेस बनाने या ऑपरेशन के लिए जावा कार्यात्मक इंटरफ़ेस का उपयोग करने की आवश्यकता है जिसके लिए दो पूर्णांक की आवश्यकता होती है और मान के रूप में वापस आती है। IntBinaryOperator

उपयोगकर्ता का उपयोग कार्यात्मक इंटरफ़ेस

interface TwoArgInterface { 

    public int operation(int a, int b); 
} 

public class MyClass { 

    public static void main(String javalatte[]) { 
     // this is lambda expression 
     TwoArgInterface plusOperation = (a, b) -> a + b; 
     System.out.println("Sum of 10,34 : " + plusOperation.operation(10, 34)); 

    } 
} 

जावा कार्यात्मक इंटरफ़ेस का उपयोग करना परिभाषित

import java.util.function.IntBinaryOperator; 

public class MyClass1 { 

    static void main(String javalatte[]) { 
     // this is lambda expression 
     IntBinaryOperator plusOperation = (a, b) -> a + b; 
     System.out.println("Sum of 10,34 : " + plusOperation.applyAsInt(10, 34)); 

    } 
} 

अन्य उदाहरण मैं बनाया है here

+0

'इंटिनरीऑपरेटर' दस्तावेज का लिंक मर चुका है। – Hendrikto

+1

यह अब तक पाया गया लैम्ब्डा का सबसे अच्छा उदाहरण है, और यह वही था जो वास्तव में मुझे अंततः 'मिल गया' था। – JimmySmithJR

22

कार्यों के लिए था है टी में 2 से अधिक पैरामीटर नहीं हैं, आप उन्हें अपने इंटरफ़ेस को परिभाषित किए बिना पास कर सकते हैं। उदाहरण के लिए, BiFunction<Integer, String, List<String>>, Integer और String

class Klass { 
    static List<String> foo(Integer a, String b) { ... } 
} 

class MyClass{ 

    static List<String> method(BiFunction<Integer, String, List<String>> fn){ 
    return fn.apply(5, "FooBar"); 
    } 
} 

List<String> lStr = MyClass.method((a, b) -> Klass.foo((Integer) a, (String) b)); 

में अपने मापदंड हैं, और List<String> अपनी वापसी प्रकार है।

केवल एक पैरामीटर के साथ एक समारोह के लिए, आप Function<T, R>, जहां T अपने पैरामीटर प्रकार है, और R अपनी वापसी मान प्रकार है उपयोग कर सकते हैं। जावा द्वारा उपलब्ध कराए गए सभी इंटरफेस के लिए इस page का संदर्भ लें।

3

लैम्ब्डा अभिव्यक्ति को तर्क के रूप में पारित किया जा सकता है। एक लैम्बडा अभिव्यक्ति को तर्क के रूप में पास करने के लिए पैरामीटर का प्रकार (जो लैम्बडा अभिव्यक्ति को तर्क के रूप में प्राप्त करता है) कार्यात्मक इंटरफ़ेस प्रकार का होना चाहिए।

अगर वहाँ एक कार्यात्मक इंटरफ़ेस है -

interface IMyFunc { 
    boolean test(int num); 
} 

और वहाँ एक फिल्टर विधि है जो सूची में पूर्णांक कहते हैं केवल अगर यह अधिक है 5. यहाँ नोट है कि फिल्टर विधि एक के रूप में कार्यात्मक इंटरफ़ेस IMyFunc है पैरामीटर का। उस मामले में लैम्ब्डा अभिव्यक्ति विधि पैरामीटर के लिए एक तर्क के रूप में पारित किया जा सकता है।

public class LambdaDemo { 
    public static List<Integer> filter(IMyFunc testNum, List<Integer> listItems) { 
     List<Integer> result = new ArrayList<Integer>(); 
     for(Integer item: listItems) { 
      if(testNum.test(item)) { 
       result.add(item); 
      } 
     } 
     return result; 
    } 
    public static void main(String[] args) { 
     List<Integer> myList = new ArrayList<Integer>(); 
     myList.add(1); 
     myList.add(4); 
     myList.add(6); 
     myList.add(7); 
     // calling filter method with a lambda expression 
     // as one of the param 
     Collection<Integer> values = filter(n -> n > 5, myList); 

     System.out.println("Filtered values " + values); 
    } 
} 
-3

लैम्बडा को पैरामीटर के रूप में उपयोग करने में लचीलापन है। यह जावा में कार्यात्मक प्रोग्रामिंग सक्षम बनाता है। > Method_body

के बाद (लैम्ब्डा प्रयोग किया जाता है) एक तरह से, आप एक विधि कार्यात्मक इंटरफ़ेस लेने को परिभाषित कर सकते है पैरामीटर के रूप में - मूल वाक्य रचना

परम है। ए। यदि आप एक विधि एक कार्यात्मक इंटरफ़ेस के अंदर घोषित परिभाषित करना चाहते हैं, कहते हैं, कार्यात्मक इंटरफ़ेसmain()

@FunctionalInterface 
interface FInterface{ 
    int callMeLambda(String temp); 
} 


class ConcreteClass{ 

    void funcUsesAnonymousOrLambda(FInterface fi){ 
     System.out.println("===Executing method arg instantiated with Lambda===")); 
    } 

    public static void main(){ 
     // calls a method having FInterface as an argument. 
     funcUsesAnonymousOrLambda(new FInterface() { 

      int callMeLambda(String temp){ //define callMeLambda(){} here.. 
       return 0; 
      } 
     } 
    } 

/***********Can be replaced by Lambda below*********/ 
     funcUsesAnonymousOrLambda((x) -> { 
      return 0; //(1) 
     } 

    } 

से कहा जाता है एक तर्क/पैरामीटर के लिए एक विधि के रूप में दिया जाता है FInterface फाई = (x) - > {वापसी 0; };

funcUsesAnonymousOrLambda (इंटरनेट);

यह ऊपर यहाँ देखा जा सकता है, कैसे एक लैम्ब्डा अभिव्यक्ति एक इंटरफेस के साथ बदला जा सकता है।

ऊपर लैम्ब्डा अभिव्यक्ति का एक विशेष उपयोग बताता है, और भी कुछ हैं। रेफरी Java 8 lambda within a lambda can't modify variable from outer lambda

संबंधित मुद्दे

 संबंधित मुद्दे