java - जावा 8 स्ट्रीम की.min()और.max():यह संकलन क्यों करता है?




java-8 java-stream (5)

नोट: यह प्रश्न एक मृत लिंक से निकला है जो पिछले SO प्रश्न था, लेकिन यहां जाता है ...

यह कोड देखें ( नोट: मुझे पता है कि यह कोड "काम नहीं करेगा" और Integer::compare का उपयोग किया जाना चाहिए - मैंने इसे लिंक किए गए प्रश्न से निकाला है ):

final ArrayList <Integer> list 
    = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());

System.out.println(list.stream().max(Integer::max).get());
System.out.println(list.stream().min(Integer::min).get());

.min() और .min() के .min() अनुसार, दोनों का तर्क एक Comparator होना चाहिए। फिर भी यहां विधि संदर्भ Integer वर्ग के स्थिर तरीकों के लिए हैं।

तो, यह बिल्कुल संकलित क्यों करता है?


Answers

Comparator एक कार्यात्मक इंटरफ़ेस है , और Integer::max उस इंटरफ़ेस का अनुपालन करता है (ऑटोबॉक्सिंग / अनबॉक्सिंग के बाद विचार किया जाता है)। इसमें दो int मान होते हैं और एक int - जैसे आप एक Comparator<Integer> से (फिर से, पूर्णांक / int अंतर को अनदेखा करने के लिए squinting) की अपेक्षा करेंगे।

हालांकि, मैं यह सही काम करने की उम्मीद नहीं करता, यह देखते हुए कि Integer.max Comparator.compare के अर्थशास्त्र का पालन नहीं करता है। और वास्तव में यह वास्तव में सामान्य रूप से काम नहीं करता है। उदाहरण के लिए, एक छोटा बदलाव करें:

for (int i = 1; i <= 20; i++)
    list.add(-i);

... और अब max मान -20 है और min मान -1 है।

इसके बजाए, दोनों कॉलों को Integer::compare करना चाहिए:

System.out.println(list.stream().max(Integer::compare).get());
System.out.println(list.stream().min(Integer::compare).get());

यह काम करता है क्योंकि Integer::min Comparator<Integer> इंटरफ़ेस के कार्यान्वयन के लिए हल करता है।

IntBinaryOperator Integer::min का विधि संदर्भ IntBinaryOperator Integer.min(int a, int b) को हल IntBinaryOperator , IntBinaryOperator को हल किया IntBinaryOperator , और संभावित रूप से IntBinaryOperator कहीं भी इसे IntBinaryOperator BinaryOperator<Integer> बनाता है।

और Stream<Integer> के min() resp max() विधियों को लागू करने के लिए Comparator<Integer> इंटरफ़ेस से पूछें।
अब यह एक विधि को हल करता है Integer compareTo(Integer o1, Integer o2)BinaryOperator<Integer> का प्रकार कौन सा है।

और इस प्रकार जादू हुआ है क्योंकि दोनों विधियां BinaryOperator<Integer>


मुझे बताएं कि यहां क्या हो रहा है, क्योंकि यह स्पष्ट नहीं है!

सबसे पहले, .max() एक उदाहरण को स्वीकार करता है ताकि स्ट्रीम में आइटम को न्यूनतम या अधिकतम खोजने के लिए एक दूसरे के खिलाफ तुलना की जा सके, कुछ इष्टतम क्रम में कि आपको बहुत ज्यादा चिंता करने की आवश्यकता नहीं है।

तो सवाल यह है कि, Integer::max क्यों स्वीकार किया जाता है? आखिरकार यह एक तुलनित्र नहीं है!

उत्तर जावा लैमडा कार्यक्षमता जावा 8 में काम करता है जिस तरह से यह एक अवधारणा पर निर्भर करता है जिसे अनौपचारिक रूप से "एकल सार विधि" इंटरफेस या "एसएएम" इंटरफेस के रूप में जाना जाता है। विचार यह है कि एक अमूर्त विधि वाला कोई इंटरफ़ेस स्वचालित रूप से किसी भी लैम्ब्डा द्वारा लागू किया जा सकता है - या विधि संदर्भ - जिसका विधि हस्ताक्षर इंटरफ़ेस पर एक विधि के लिए एक मिलान है। तो Comparator इंटरफेस (सरल संस्करण) की जांच:

public Comparator<T> {
    int compare(T o1, T o2);
}

यदि कोई विधि एक Comparator<Integer> , तो यह अनिवार्य रूप से इस हस्ताक्षर की तलाश में है:

int xxx(Integer o1, Integer o2);

मैं "xxx" का उपयोग करता हूं क्योंकि विधि का उपयोग मिलान उद्देश्यों के लिए नहीं किया जाता है

इसलिए, Integer.min(int a, int b) और Integer.max(int a, int b) दोनों पर्याप्त हैं कि ऑटोबॉक्सिंग इसे एक विधि संदर्भ में एक Comparator<Integer> रूप में प्रकट करने की अनुमति देगा।


डेविड एम। लॉयड द्वारा दी गई जानकारी के अलावा कोई भी यह जोड़ सकता है कि जिस तंत्र को इसे अनुमति देने की अनुमति दी जाती है उसे लक्ष्य टाइपिंग कहा जाता है।

विचार यह है कि कंपाइलर लैम्ब्डा अभिव्यक्तियों या विधि संदर्भों को निर्दिष्ट करता है, केवल अभिव्यक्ति पर ही निर्भर नहीं होता है, बल्कि यह कहां उपयोग किया जाता है।

अभिव्यक्ति का लक्ष्य वह चर है जिसके परिणामस्वरूप उसका परिणाम असाइन किया गया है या पैरामीटर जिसके परिणामस्वरूप पारित किया गया है।

लैम्ब्डा अभिव्यक्तियों और विधि संदर्भों को एक प्रकार असाइन किया जाता है जो उनके लक्ष्य के प्रकार से मेल खाता है, यदि ऐसा कोई प्रकार पाया जा सकता है।

अधिक जानकारी के लिए जावा ट्यूटोरियल में टाइप इनफरेंस सेक्शन देखें।


जावा में प्रत्येक लूप अंतर्निहित इटरेटर तंत्र का उपयोग करता है। तो यह निम्नलिखित के समान है:

Iterator<String> iterator = someList.iterator();

while (iterator.hasNext()) {
  String item = iterator.next();
  System.out.println(item);
}




java java-8 java-stream