11
import java.util.function.*; 

class Test { 
    void test(int foo, Consumer<Integer> bar) { } 
    void test(long foo, Consumer<Long> bar) { } 
    void test(float foo, Consumer<Float> bar) { } 
    void test(double foo, Consumer<Double> bar) { } 
} 

साथ संभावित अस्पष्ट है। यह प्रोग्राम नि: शुल्क चेतावनी दे रहा है:चेतावनी: जब मैं इस <code>javac -Xlint Test.java</code> साथ संकलन मैं चेतावनी के एक जोड़े मिल [भार के] विधि एम 1 विधि एम 2

import java.util.function.*; 

class Test { 
    void test(int foo, Supplier<Integer> bar) { } 
    void test(long foo, Supplier<Long> bar) { } 
    void test(float foo, Supplier<Float> bar) { } 
    void test(double foo, Supplier<Double> bar) { } 
} 

वह क्यों है? इस चेतावनी का क्या अर्थ है? इन तरीकों को अस्पष्ट कैसे हैं? चेतावनी दबाने के लिए सुरक्षित है?

+0

जब आप चेतावनी के बारे में चेतावनी देने का प्रयास करते हैं तो क्या होता है? –

+1

ऐसा प्रतीत होता है कि चेतावनी केवल तब जारी की जाएगी जब: ए। यह एक कार्यात्मक इंटरफ़ेस है (यानी उपभोक्ता, प्रदायक), और बी। इंटरफ़ेस के किसी भी तरीके में किसी भी पैरामीटर शामिल हैं ... एक परीक्षण के रूप में मैंने उपभोक्ता/प्रदायक इंटरफेस की अपनी प्रतियां बनाई और उनके साथ twiddled। अफसोस की बात है कि मुझे जावा फंक्शनल के बारे में पता नहीं है कि यह जानने के लिए क्यों चेतावनी दी जाएगी। – Kai

+0

सुधार: बिंदु ए गलत है, इसे एक कार्यात्मक इंटरफ़ेस होने की आवश्यकता नहीं है, केवल एक इंटरफ़ेस (क्लास कोई चेतावनी नहीं देता है) केवल एक (गैर-डिफ़ॉल्ट) विधि परिभाषित किया गया है। इसके अलावा, मैंने टेस्ट (ऑब्जेक्ट, कंज्यूमर) v.s. जैसे संदिग्ध होने के लिए असंभव के बगल में कुछ (परीक्षण, int, उपभोक्ता) के पैरामीटर बदल दिए हैं। परीक्षण (मानचित्र, उपभोक्ता) और फिर भी चेतावनी अभी भी फेंक दी गई है। इस प्रकार, जब तक कि आप कुछ वास्तव में निराला प्रोग्रामिंग नहीं करते हैं, मुझे नहीं लगता कि आपको इसके बारे में चिंता करने की आवश्यकता होगी। – Kai

उत्तर

16

ये चेतावनियां ओवरलोड रिज़ॉल्यूशन, लक्ष्य टाइपिंग और टाइप अनुमान के बीच मज़ेदार चौराहे के कारण होती हैं। कंपाइलर आपके लिए थोड़ा आगे सोच रहा है और आपको चेतावनी दे रहा है क्योंकि अधिकांश लैम्बडा स्पष्ट रूप से घोषित प्रकारों के बिना लिखे गए हैं।

test(1, i -> { }); 

i के प्रकार क्या है: उदाहरण के लिए, इस कॉल पर विचार? कंपाइलर इसे अधिभारित नहीं कर सकता है जब तक कि यह ओवरलोड रिज़ॉल्यूशन पूरा नहीं हो जाता ... लेकिन मान 1 सभी चार ओवरलोड से मेल खाता है। जो भी अधिभार चुना जाता है वह दूसरे तर्क के लक्ष्य प्रकार को प्रभावित करेगा, जो बदले में i के लिए अनुमानित प्रकार को प्रभावित करेगा।

error: reference to test is ambiguous 
      both method test(float,Consumer<Float>) in Test and 
      method test(double,Consumer<Double>) in Test match 

(दिलचस्प है, यह float और double भार के उल्लेख है, लेकिन: वहाँ वास्तव में पर्याप्त जानकारी यहाँ संकलक तय करने के लिए जो करने के लिए विधि कॉल करने, इसलिए इस लाइन वास्तव में एक संकलन समय त्रुटि में परिणाम होगा नहीं है अगर आप इनमें से किसी एक को बाहर टिप्पणी, आप long अधिभार के संबंध में एक ही त्रुटि मिलती है।)

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

संकलक विधि घोषणाओं पर चेतावनियां जारी कर रहा है यह इंगित करने के लिए कि प्रोग्रामर संभावित कोड जो इन विधियों में से एक को कॉल करने के लिए लिखता है (ऊपर दिखाया गया है) परिणामस्वरूप संकलन-समय त्रुटि होगी।

कॉल को स्पष्ट करने के लिए, एक के बजाय

test(1, (Integer i) -> { }); 

लिख सकते हैं या i पैरामीटर के लिए कुछ अन्य स्पष्ट प्रकार की घोषणा करने के लिए होगा। एक और तरीका लैम्ब्डा से पहले एक कास्ट जोड़ना है:

test(1, (Consumer<Integer>)i -> { }); 

लेकिन यह तर्कसंगत रूप से खराब है। आप शायद नहीं चाहते कि आपके एपीआई के कॉलर्स को कॉल के हर बिंदु पर इस तरह की चीज के साथ कुश्ती करना पड़े।

ये चेतावनियां Supplier मामले के लिए नहीं होती हैं, क्योंकि प्रदायक के प्रकार को स्थानीय तर्क के माध्यम से किसी भी प्रकार के अनुमान के बिना निर्धारित किया जा सकता है।

आप शायद इस एपीआई को एक साथ रखने के तरीके पर पुनर्विचार करना चाहेंगे।यदि आप वास्तव में उन तर्क प्रकारों के साथ विधियों को चाहते हैं, तो आप testInt, testLong आदि विधियों का नाम बदलने के लिए अच्छा प्रदर्शन कर सकते हैं और पूरी तरह ओवरलोडिंग से बच सकते हैं। ध्यान दें कि जावा एसई एपीआई ने इसी तरह के मामलों में ऐसा किया है, जैसे comparingInt, comparingLong, और comparingDoubleComparator पर; और mapToInt, mapToLong, और पर mapToDouble भी।

+0

बहुत अच्छी व्याख्या! पढ़ने के बाद कोई सवाल नहीं छोड़ा गया। – TWiStErRob

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