लैम्ब्डा एक्सप्रेशन और जेनेरिक विधि


111

मान लीजिए कि मैं एक सामान्य इंटरफ़ेस है:

interface MyComparable<T extends Comparable<T>>  {
    public int compare(T obj1, T obj2);
}

और एक विधि sort:

public static <T extends Comparable<T>> 
       void sort(List<T> list, MyComparable<T> comp) {
    // sort the list
}

मैं इस पद्धति को लागू कर सकता हूं और तर्क के रूप में एक लंबोदर अभिव्यक्ति पारित कर सकता हूं:

List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));

यह ठीक काम करेगा।

लेकिन अब अगर मैं इंटरफ़ेस को गैर-जेनेरिक, और विधि को सामान्य बनाता हूँ:

interface MyComparable {
    public <T extends Comparable<T>> int compare(T obj1, T obj2);
}

public static <T extends Comparable<T>> 
       void sort(List<T> list, MyComparable comp) {
}

और फिर इस तरह से आह्वान करें:

List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));

यह संकलन नहीं है। यह यह कहते हुए लंबोदर अभिव्यक्ति में त्रुटि दिखाता है:

"लक्ष्य विधि सामान्य है"

ठीक है, जब मैंने इसका उपयोग करके संकलित किया javac, तो यह निम्नलिखित त्रुटि दिखाता है:

SO.java:20: error: incompatible types: cannot infer type-variable(s) T#1
        sort(list, (a, b) -> a.compareTo(b));
            ^
    (argument mismatch; invalid functional descriptor for lambda expression
      method <T#2>(T#2,T#2)int in interface MyComparable is generic)
  where T#1,T#2 are type-variables:
    T#1 extends Comparable<T#1> declared in method <T#1>sort(List<T#1>,MyComparable)
    T#2 extends Comparable<T#2> declared in method <T#2>compare(T#2,T#2)
1 error

इस त्रुटि संदेश से, ऐसा लगता है जैसे संकलक टाइप तर्कों का अनुमान लगाने में सक्षम नहीं है। क्या यह मामला है? यदि हाँ, तो ऐसा क्यों हो रहा है?

मैंने विभिन्न तरीकों की कोशिश की, इंटरनेट के माध्यम से खोज की। तब मुझे यह JavaCodeGeeks लेख मिला , जो एक रास्ता दिखाता है, इसलिए मैंने कोशिश की:

sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));

जो फिर से काम नहीं करता है, उस लेख के विपरीत जो यह दावा करता है कि यह काम करता है। संभव है कि यह कुछ शुरुआती बिल्ड में काम करता था।

तो मेरा सवाल यह है कि क्या जेनेरिक पद्धति के लिए लैम्ब्डा अभिव्यक्ति बनाने का कोई तरीका है? मैं एक विधि संदर्भ का उपयोग करके ऐसा कर सकता हूं, हालांकि एक विधि बनाकर:

public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
    return obj1.compareTo(obj2);
}

कुछ वर्ग कहते हैं SO, और इसे पास करें:

sort(list, SO::compare);

जवाबों:


117

आप एक का उपयोग नहीं कर सकते हैं लैम्ब्डा अभिव्यक्ति एक के लिए कार्यात्मक इंटरफ़ेस है, अगर में विधि कार्यात्मक इंटरफ़ेस है प्रकार पैरामीटरJLS8 में अनुभाग .215.27.3 देखें :

एक लैम्ब्डा अभिव्यक्ति लक्ष्य प्रकार के साथ संगत है [..] टी अगर टी एक कार्यात्मक इंटरफ़ेस प्रकार (§9.8) और अभिव्यक्ति है अनुकूल के समारोह प्रकार के साथ [..] टी [..] एक लैम्ब्डा अभिव्यक्ति है अनुकूल फ़ंक्शन प्रकार के साथ यदि निम्न में से सभी सत्य हैं:

  • फ़ंक्शन प्रकार में कोई प्रकार के पैरामीटर नहीं हैं
  • [..]

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

17
मुझे यकीन है कि इस प्रतिबंध का एक अच्छा कारण है। यह क्या है?
सैंड्रो

6
@ सैंड्रो: लैम्बडा एक्सप्रेशन के लिए टाइप पैरामीटर घोषित करने के लिए बस कोई सिंटैक्स नहीं है। और ऐसा वाक्यविन्यास बहुत जटिल होगा। ध्यान रखें कि पार्सर अभी भी अन्य कानूनी जावा निर्माणों के अलावा प्रकार पैरामीटर के साथ इस तरह के एक लंबो अभिव्यक्ति को बताने में सक्षम होना चाहिए। इस प्रकार आपको विधि संदर्भों का सहारा लेना होगा। लक्ष्य पद्धति एक स्थापित वाक्यविन्यास का उपयोग करके प्रकार के मापदंडों की घोषणा कर सकती है
होल्गर

2
@ होलगर अभी भी, जहां प्रकार के पैरामीटर ऑटो-कटौती किए जा सकते हैं, कंपाइलर एक कैपचर प्रकार को डीकोड कर सकता है जैसा कि आप जब सेट करते हैं जैसे कि सेट <?> और उन कैप्चर किए गए प्रकारों के साथ टाइप-चेक करते हैं। यकीन है, कि उन्हें शरीर में टाइप-पैरामीटर के रूप में देना असंभव है, लेकिन अगर आपको इसकी आवश्यकता होगी, तो विधि संदर्भों का सहारा लेना एक अच्छा विकल्प है
WorldSEnder

17

विधि संदर्भ का उपयोग करते हुए, मुझे तर्क पास करने का अन्य तरीका मिला:

List<String> list = Arrays.asList("a", "b", "c");        
sort(list, Comparable::<String>compareTo);

3

बस पॉइंट कम्पाइलर जेनेरिक कम्पैक्टर के उचित संस्करण के साथ (Comparator<String>)

तो जवाब होगा

sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));


2
incompatible types: java.util.Comparator<java.lang.String> cannot be converted to MyComparableऔर MyComparableसामान्य नहीं है (कोई प्रकार नहीं) तो (MyComparable<String>)यह भी काम नहीं करेगा
user85421

1
पता नहीं कैसे आप @CarlosHeuberger कोड टाइप कर रहे हैं, लेकिन यह मेरे लिए बहुत अच्छी तरह से काम करता है, यही वह है जिसकी मुझे तलाश थी।
इवान पेरेल्स एम।

@IvanPeralesM। 2 महीने के बाद ... मैंने आपका कोड कॉपी किया और पेस्ट किया और आपकी तरह की लाइन के ऊपर कॉपी और पेस्ट किया - बस यहीं, जैसे: ideone.com/YNwBbF ! क्या आप वाकई कोड के ऊपर टाइप किया है? का उपयोग कर Compartor?
user85421

नहीं, न ही मैं जवाब के पीछे के विचार का उपयोग करता हूं, यह बताने के लिए कि यह किस प्रकार का है और यह काम किया है।
इवान पेरेल्स एम।

@IvanPeralesM। अच्छा, फिर मेरी "टाइपिंग" से आपको क्या समस्या है? उत्तर, जैसा कि पोस्ट किया गया है, काम नहीं करता है।
user85421

0

क्या आपका मतलब इस तरह की किसी चीज से है?:

<T,S>(T t, S s)->...

यह मेमना किस प्रकार का है? आप जावा में व्यक्त नहीं कर सकते हैं और इसलिए इस अभिव्यक्ति को एक फ़ंक्शन अनुप्रयोग में नहीं लिख सकते हैं और अभिव्यक्तियों को रचना के योग्य होना चाहिए।

काम करने के लिए आपको जावा में रैंक 2 प्रकारों के लिए समर्थन की आवश्यकता होगी ।

विधियों को सामान्य होने की अनुमति है, लेकिन इसलिए आप उन्हें अभिव्यक्ति के रूप में उपयोग नहीं कर सकते हैं। हालाँकि, इससे पहले कि आप उन्हें पारित कर सकें, सभी आवश्यक सामान्य प्रकारों की विशेषज्ञता के द्वारा लंबोदर अभिव्यक्ति को कम किया जा सकता है:ClassName::<TypeName>methodName


1
"Of what type is this lambda? You couldn't express that in Java..."प्रकार संदर्भ का उपयोग कर अनुमान लगाया जाएगा, बस किसी अन्य भेड़ के बच्चे की तरह। एक मेमने का प्रकार स्पष्ट रूप से भेड़ के बच्चे में ही व्यक्त नहीं किया जाता है।
Kröw
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.