क्यों एक प्रकार का पैरामीटर मजबूत है तो एक विधि पैरामीटर


12

यही वजह है कि

public <R, F extends Function<T, R>> Builder<T> withX(F getter, R returnValue) {...}

अधिक सख्त

public <R> Builder<T> with(Function<T, R> getter, R returnValue) {...}

यह अनुवर्ती समय पर जाँच नहीं किए जाने वाले लंबोदर रिटर्न टाइप क्यों है पर एक अनुवर्ती है । मैंने withX()जैसे विधि का उपयोग कर पाया

.withX(MyInterface::getLength, "I am not a Long")

वांछित संकलन समय त्रुटि पैदा करता है:

प्रकार का गेटलिफ्टर () प्रकार बिल्डर से। Example.MyInterface लंबा है, यह डिस्क्रिप्टर के रिटर्न प्रकार के साथ असंगत है: स्ट्रिंग

जबकि विधि का उपयोग with()नहीं करता है।

पूरा उदाहरण:

import java.util.function.Function;

public class SO58376589 {
  public static class Builder<T> {
    public <R, F extends Function<T, R>> Builder<T> withX(F getter, R returnValue) {
      return this;
    }

    public <R> Builder<T> with(Function<T, R> getter, R returnValue) {
      return this;
    }

  }

  static interface MyInterface {
    public Long getLength();
  }

  public static void main(String[] args) {
    Builder<MyInterface> b = new Builder<MyInterface>();
    Function<MyInterface, Long> getter = MyInterface::getLength;
    b.with(getter, 2L);
    b.with(MyInterface::getLength, 2L);
    b.withX(getter, 2L);
    b.withX(MyInterface::getLength, 2L);
    b.with(getter, "No NUMBER"); // error
    b.with(MyInterface::getLength, "No NUMBER"); // NO ERROR !!
    b.withX(getter, "No NUMBER"); // error
    b.withX(MyInterface::getLength, "No NUMBER"); // error !!!
  }
}

javac SO58376589.java

SO58376589.java:32: error: method with in class Builder<T> cannot be applied to given types;
    b.with(getter, "No NUMBER"); // error
     ^
  required: Function<MyInterface,R>,R
  found: Function<MyInterface,Long>,String
  reason: inference variable R has incompatible bounds
    equality constraints: Long
    lower bounds: String
  where R,T are type-variables:
    R extends Object declared in method <R>with(Function<T,R>,R)
    T extends Object declared in class Builder
SO58376589.java:34: error: method withX in class Builder<T> cannot be applied to given types;
    b.withX(getter, "No NUMBER"); // error
     ^
  required: F,R
  found: Function<MyInterface,Long>,String
  reason: inference variable R has incompatible bounds
    equality constraints: Long
    lower bounds: String
  where F,R,T are type-variables:
    F extends Function<MyInterface,R> declared in method <R,F>withX(F,R)
    R extends Object declared in method <R,F>withX(F,R)
    T extends Object declared in class Builder
SO58376589.java:35: error: incompatible types: cannot infer type-variable(s) R,F
    b.withX(MyInterface::getLength, "No NUMBER"); // error
           ^
    (argument mismatch; bad return type in method reference
      Long cannot be converted to String)
  where R,F,T are type-variables:
    R extends Object declared in method <R,F>withX(F,R)
    F extends Function<T,R> declared in method <R,F>withX(F,R)
    T extends Object declared in class Builder
3 errors

विस्तारित उदाहरण

निम्न उदाहरण एक सप्लायर को उबला हुआ विधि और प्रकार के पैरामीटर के विभिन्न व्यवहार को दर्शाता है। इसके अतिरिक्त यह एक प्रकार के पैरामीटर के लिए उपभोक्ता व्यवहार के अंतर को दर्शाता है। और यह दिखाता है कि यह एक अंतर नहीं बनाता है यह एक विधि पैरामीटर के लिए एक उपभोक्ता या आपूर्तिकर्ता है।

import java.util.function.Consumer;
import java.util.function.Supplier;
interface TypeInference {

  Number getNumber();

  void setNumber(Number n);

  @FunctionalInterface
  interface Method<R> {
    TypeInference be(R r);
  }

  //Supplier:
  <R> R letBe(Supplier<R> supplier, R value);
  <R, F extends Supplier<R>> R letBeX(F supplier, R value);
  <R> Method<R> let(Supplier<R> supplier);  // return (x) -> this;

  //Consumer:
  <R> R lettBe(Consumer<R> supplier, R value);
  <R, F extends Consumer<R>> R lettBeX(F supplier, R value);
  <R> Method<R> lett(Consumer<R> consumer);


  public static void main(TypeInference t) {
    t.letBe(t::getNumber, (Number) 2); // Compiles :-)
    t.lettBe(t::setNumber, (Number) 2); // Compiles :-)
    t.letBe(t::getNumber, 2); // Compiles :-)
    t.lettBe(t::setNumber, 2); // Compiles :-)
    t.letBe(t::getNumber, "NaN"); // !!!! Compiles :-(
    t.lettBe(t::setNumber, "NaN"); // Does not compile :-)

    t.letBeX(t::getNumber, (Number) 2); // Compiles :-)
    t.lettBeX(t::setNumber, (Number) 2); // Compiles :-)
    t.letBeX(t::getNumber, 2); // !!! Does not compile  :-(
    t.lettBeX(t::setNumber, 2); // Compiles :-)
    t.letBeX(t::getNumber, "NaN"); // Does not compile :-)
    t.lettBeX(t::setNumber, "NaN"); // Does not compile :-)

    t.let(t::getNumber).be(2); // Compiles :-)
    t.lett(t::setNumber).be(2); // Compiles :-)
    t.let(t::getNumber).be("NaN"); // Does not compile :-)
    t.lett(t::setNumber).be("NaN"); // Does not compile :-)
  }
}

1
उत्तरार्द्ध के साथ हस्तक्षेप के कारण। हालांकि ये दोनों उपयोग-मामले पर आधारित हैं, जिन्हें लागू करने की आवश्यकता है। आपके लिए, पूर्व सख्त और अच्छा हो सकता है। लचीलेपन के लिए, कोई और व्यक्ति बाद की पसंद कर सकता है।
नमन

क्या आप इसे ग्रहण में संकलित करने का प्रयास कर रहे हैं? आपके द्वारा चिपकाए गए प्रारूप के त्रुटि स्ट्रिंग के लिए खोज करना यह एक ग्रहण (एक्ज) विशिष्ट त्रुटि है। क्या आपको वही समस्या आती है जब कच्चे javacया एक निर्माण उपकरण जैसे कि ग्रेडल या मावेन के साथ संकलन किया जाता है ?
user31601

@ user31601 मैंने javac आउटपुट के साथ एक पूर्ण उदाहरण जोड़ा। त्रुटि संदेश थोड़ा अलग हैं, लेकिन फिर भी ग्रहण और javac समान व्यवहार रखते हैं
जुकज़ी

जवाबों:


12

यह वास्तव में एक दिलचस्प सवाल है। जवाब, मुझे डर है, जटिल है।

tl; डॉ

अंतर को काम करने में जावा के प्रकार के अनुमान विनिर्देश के कुछ काफी गहराई से पढ़ने को शामिल किया गया है , लेकिन मूल रूप से यह उबलता है:

  • अन्य सभी चीजें समान हैं, कंपाइलर सबसे विशिष्ट प्रकार को संक्रमित करता है जो यह कर सकता है।
  • हालांकि, अगर यह एक प्रकार के पैरामीटर के लिए एक प्रतिस्थापन पा सकता है जो सभी आवश्यकताओं को पूरा करता है, तो संकलन सफल होगा, हालांकि प्रतिस्थापन अस्पष्ट हो जाता है।
  • के लिए withएक (स्पष्ट रूप से अस्पष्ट) प्रतिस्थापन है जो सभी आवश्यकताओं को पूरा करता है R:Serializable
  • इसके लिए withX, अतिरिक्त प्रकार के पैरामीटर की शुरूआत बाधा को ध्यान में रखते हुए, पहले Fहल करने के लिए मजबूर Rकरती है F extends Function<T,R>R(बहुत अधिक विशिष्ट) को हल करता है, Stringजिसका अर्थ है कि असफलता का अनुमान F

यह अंतिम गोली बिंदु सबसे महत्वपूर्ण है, लेकिन सबसे हाथ में लहराती भी है। मैं इसे बेहतर बनाने के बेहतर तरीके के बारे में नहीं सोच सकता, इसलिए यदि आप अधिक विवरण चाहते हैं, तो मेरा सुझाव है कि आप नीचे दिए गए पूर्ण विवरण को पढ़ें।

क्या यह अभिप्रेत व्यवहार है?

मैं एक अंग पर यहाँ जा रहा हूँ, और कहते हैं कि नहीं

मैं सुझाव नहीं दे रहा हूं कि कल्पना में एक बग है, और अधिक कि (मामले में withX) भाषा डिजाइनरों ने अपने हाथों को ऊपर रखा है और कहा है "कुछ परिस्थितियां हैं जहां प्रकार का अनुमान बहुत कठिन हो जाता है, इसलिए हम बस विफल हो जाएंगे" । भले ही withXआप चाहते हैं कि प्रतीत होने के लिए सम्मान के साथ संकलक का व्यवहार , मैं इस बात पर विचार करूंगा कि वर्तमान में एक सकारात्मक डिजाइन के निर्णय के बजाय वर्तमान कल्पना के पक्ष-प्रभाव का होना।

यह मायने रखता है, क्योंकि यह सवाल सूचित करता है कि क्या मुझे अपने आवेदन डिजाइन में इस व्यवहार पर भरोसा करना चाहिए? मेरा तर्क है कि आपको नहीं करना चाहिए, क्योंकि आप इस बात की गारंटी नहीं दे सकते कि भविष्य के संस्करण इस तरह से व्यवहार करते रहेंगे।

हालांकि यह सच है कि भाषा डिजाइनर मौजूदा अनुप्रयोगों को तोड़ने के लिए बहुत कोशिश करते हैं जब वे अपनी कल्पना / डिजाइन / संकलक को अपडेट करते हैं, तो समस्या यह है कि जिस व्यवहार पर आप भरोसा करना चाहते हैं वह वह है जहां कंपाइलर वर्तमान में विफल रहता है (अर्थात मौजूदा एप्लिकेशन नहीं )। लैंगगेज अपडेट गैर-संकलन कोड को हर समय संकलन कोड में बदल देते हैं। उदाहरण के लिए, निम्नलिखित कोड को जावा 7 में संकलित नहीं करने की गारंटी दी जा सकती है , लेकिन जावा 8 में संकलित किया जाएगा :

static Runnable x = () -> System.out.println();

आपका उपयोग-मामला अलग नहीं है।

एक और कारण मैं आपके withXविधि का उपयोग करने के बारे में सतर्क रहूँगा जो कि Fस्वयं पैरामीटर है। आम तौर पर, एक विधि पर एक सामान्य प्रकार के पैरामीटर (जो रिटर्न प्रकार में प्रकट नहीं होता है) एक साथ हस्ताक्षर के कई हिस्सों के प्रकारों को बांधने के लिए मौजूद है। यह कह रहा है:

मुझे परवाह नहीं है कि क्या Tहै, लेकिन यह सुनिश्चित करना चाहता हूं कि मैं जहां भी उपयोग करूं, Tवह उसी प्रकार का हो।

तार्किक रूप से, फिर, हम उम्मीद करेंगे कि प्रत्येक प्रकार का पैरामीटर कम से कम दो बार एक विधि हस्ताक्षर में दिखाई दे, अन्यथा "यह कुछ भी नहीं कर रहा है"। Fआपके withXहस्ताक्षर में केवल एक बार दिखाई देता है, जो मुझे एक प्रकार के पैरामीटर का उपयोग करने का सुझाव देता है जो भाषा की इस विशेषता के इरादे से इनलाइन नहीं है ।

एक वैकल्पिक कार्यान्वयन

इसे थोड़ा और अधिक "इच्छित व्यवहार" तरीके से लागू करने का एक तरीका यह होगा कि आप अपने withतरीके को 2 की श्रृंखला में विभाजित करें :

public class Builder<T> {

    public final class With<R> {
        private final Function<T,R> method;

        private With(Function<T,R> method) {
            this.method = method;
        }

        public Builder<T> of(R value) {
            // TODO: Body of your old 'with' method goes here
            return Builder.this;
        }
    }

    public <R> With<R> with(Function<T,R> method) {
        return new With<>(method);
    }

}

यह तो निम्नानुसार इस्तेमाल किया जा सकता है:

b.with(MyInterface::getLong).of(1L); // Compiles
b.with(MyInterface::getLong).of("Not a long"); // Compiler error

इसमें आपके जैसा कोई बाहरी प्रकार का पैरामीटर शामिल नहीं withXहै। विधि को दो हस्ताक्षरों में तोड़कर, यह इस बात की मंशा को भी बेहतर ढंग से व्यक्त करता है कि आप क्या करने की कोशिश कर रहे हैं, एक प्रकार की सुरक्षा से:

  • पहली विधि एक वर्ग ( With) स्थापित करती है जो विधि संदर्भ के आधार पर प्रकार को परिभाषित करती है।
  • Scond विधि ( of) रोकें के प्रकार valueक्या आप पहले सेट के साथ संगत होना करने के लिए।

भाषा का एक भविष्य का एकमात्र तरीका यह संकलित करने में सक्षम होगा यदि कार्यान्वित पूर्ण बतख-टाइपिंग, जो कि संभावना नहीं है।

एक अंतिम नोट इस पूरी बात को अप्रासंगिक बनाने के लिए: मुझे लगता है कि मॉकिटो (और विशेष रूप से इसकी स्टबिंग कार्यक्षमता) मूल रूप से पहले से ही ऐसा कर सकता है जिसे आप अपने "प्रकार सुरक्षित जेनेरिक बिल्डर" के साथ हासिल करने की कोशिश कर रहे हैं। शायद आप इसके बजाय बस का उपयोग कर सकते हैं?

पूर्ण (ईश) व्याख्या

मैं के माध्यम से काम करने के लिए जा रहा हूँ प्रकार निष्कर्ष प्रक्रिया दोनों के लिए withऔर withX। यह काफी लंबा है, इसलिए इसे धीरे-धीरे लें। लंबे होने के बावजूद, मैंने अभी भी बहुत सारे विवरणों को छोड़ दिया है। आप अपने आप को समझाने के लिए और अधिक विवरण (लिंक का पालन करें) की युक्ति का उल्लेख करना चाह सकते हैं कि मैं सही हूं (मैंने अच्छी तरह से गलती की होगी)।

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

public class TypeInference {

    static long getLong() { return 1L; }

    static <R> void with(Supplier<R> supplier, R value) {}
    static <R, F extends Supplier<R>> void withX(F supplier, R value) {}

    public static void main(String[] args) {
        with(TypeInference::getLong, "Not a long");       // Compiles
        withX(TypeInference::getLong, "Also not a long"); // Does not compile
    }

}

आइए बदले में प्रत्येक विधि आह्वान के लिए टाइप प्रयोज्यता निष्कर्ष और प्रकार अनुमान प्रक्रिया के माध्यम से काम करते हैं:

with

हमारे पास है:

with(TypeInference::getLong, "Not a long");

प्रारंभिक बाउंड सेट, बी 0 , है:

  • R <: Object

सभी पैरामीटर अभिव्यक्ति प्रयोज्यता के अनुकूल हैं ।

इसलिए, प्रयोज्यता अनुमान , सी , के लिए प्रारंभिक बाधा निर्धारित है:

  • TypeInference::getLong के साथ संगत है Supplier<R>
  • "Not a long" के साथ संगत है R

यह बी सेट के 2 को कम करता है :

  • R <: Object( बी 0 से )
  • Long <: R (पहले बाधा से)
  • String <: R (दूसरे बाधा से)

चूंकि इसमें बाध्य ' गलत ' शामिल नहीं है , और (मुझे लगता है) सफल होने (देने ) का संकल्प है , तो आह्वान लागू है।RSerializable

इसलिए, हम आह्वान करते हैं कि हम आह्वान के प्रकार पर जाएं ।

नया बाधा सेट, सी , संबंधित इनपुट और आउटपुट चर के साथ है:

  • TypeInference::getLong के साथ संगत है Supplier<R>
    • इनपुट चर: कोई नहीं
    • आउटपुट चर: R

इसमें इनपुट और आउटपुट चर के बीच कोई अन्य निर्भरता नहीं है , इसलिए इसे एक ही चरण में कम किया जा सकता है , और अंतिम बाउंड सेट, बी 4 , बी 2 के समान है । इसलिए, संकल्प पहले की तरह सफल हुआ, और संकलक ने राहत की सांस ली!

withX

हमारे पास है:

withX(TypeInference::getLong, "Also not a long");

प्रारंभिक बाउंड सेट, बी 0 , है:

  • R <: Object
  • F <: Supplier<R>

केवल दूसरा पैरामीटर अभिव्यक्ति प्रयोज्यता के अनुकूल है । पहला वाला ( TypeInference::getLong) नहीं है, क्योंकि यह निम्नलिखित स्थिति को पूरा करता है:

यदि mएक सामान्य विधि है और विधि आह्वान स्पष्ट प्रकार के तर्क प्रदान नहीं करता है, तो स्पष्ट रूप से टाइप की गई लंबोदर अभिव्यक्ति या एक सटीक विधि संदर्भ अभिव्यक्ति जिसके लिए संबंधित लक्ष्य प्रकार (हस्ताक्षर से प्राप्त m) एक प्रकार का पैरामीटर है m

इसलिए, प्रयोज्यता अनुमान , सी , के लिए प्रारंभिक बाधा निर्धारित है:

  • "Also not a long" के साथ संगत है R

यह बी सेट के 2 को कम करता है :

  • R <: Object( बी 0 से )
  • F <: Supplier<R>( बी 0 से )
  • String <: R (अड़चन से)

फिर, चूंकि इसमें बाध्य ' गलत ' नहीं है, और सफल होने (देने ) का संकल्प है , तो आह्वान लागू है।RString

एक बार फिर आह्वान के प्रकार

इस बार, नया बाधा सेट, C , संबंधित इनपुट और आउटपुट चर के साथ है:

  • TypeInference::getLong के साथ संगत है F
    • इनपुट चर: F
    • आउटपुट चर: कोई नहीं

फिर से, हमारे पास इनपुट और आउटपुट चर के बीच कोई अन्य निर्भरता नहीं है । हालांकि इस समय, वहाँ है एक इनपुट चर ( F,) तो हम चाहिए हल प्रयास करने से पहले इस कमी । तो, हम अपने बाउंड सेट बी 2 से शुरू करते हैं ।

  1. हम एक उपसमूह Vइस प्रकार निर्धारित करते हैं:

    हल करने के लिए प्रवेश चर के एक सेट को देखते हुए, Vइस सेट के संघ और सभी चर होने चाहिए, जिस पर इस सेट में कम से कम एक चर का संकल्प निर्भर करता है।

    बी 2 में दूसरे बाउंड द्वारा , Fनिर्भर करने का संकल्प R, इसलिए V := {F, R}

  2. हम Vनियम के अनुसार एक सबसेट चुनते हैं :

    आइए , सभी के लिए इस तरह { α1, ..., αn }के अनइंस्टैंटेड वेरिएबल्स का एक गैर-रिक्त उपसमूह बनें , यदि कोई वैरिएबल के रिज़ॉल्यूशन पर निर्भर करता है , तो या तो एक तात्कालिकता है या कुछ ऐसा है ; (ii) इस संपत्ति के साथ कोई गैर-खाली उचित उपसमूह मौजूद नहीं है।Vi (1 ≤ i ≤ n)αiββjβ = αj{ α1, ..., αn }

    उस का एकमात्र सबसेट Vइस संपत्ति को संतुष्ट करता है {R}

  3. तीसरी बाउंड ( String <: R) का उपयोग करके हम R = Stringइसे अपने बाउंड सेट में तुरंत शामिल करते हैं और शामिल करते हैं। Rअब हल हो गया है, और प्रभावी रूप से दूसरा बाध्य हो गया है F <: Supplier<String>

  4. (संशोधित) दूसरे बाउंड का उपयोग करना, हम तुरंत करते हैं F = Supplier<String>Fअब हल हो गया है।

अब Fयह हल हो गया है, हम कमी के साथ आगे बढ़ सकते हैं , नए अवरोध का उपयोग करते हुए:

  1. TypeInference::getLong के साथ संगत है Supplier<String>
  2. ... कम करने के Long लिए संगत है String
  3. ... जो झूठ को कम करता है

... और हमें एक संकलक त्रुटि मिलती है!


'विस्तारित उदाहरण' पर अतिरिक्त नोट

विस्तारित उदाहरण में कुछ दिलचस्प मामलों है कि सीधे ऊपर कामकाज में शामिल नहीं हैं पर सवाल दिखता में:

  • जहाँ मान प्रकार विधि वापसी प्रकार का एक उपप्रकार है ( Integer <: Number)
  • जहाँ क्रियात्मक इंटरफ़ेस अनुमानात्मक प्रकार में विरोधाभासी है (अर्थात Consumerइसके बजाय Supplier)

विशेष रूप से, दिए गए इनवोकेशन में से 3 संभावित रूप से 'अलग' संकलक व्यवहार का सुझाव देने के लिए बाहर खड़े होते हैं जो स्पष्टीकरण में वर्णित हैं:

t.lettBe(t::setNumber, "NaN"); // Does not compile :-)

t.letBeX(t::getNumber, 2); // !!! Does not compile  :-(
t.lettBeX(t::setNumber, 2); // Compiles :-)

इन 3 में से दूसरा ठीक withXऊपर की प्रक्रिया के समान ही गुजर जाएगा (बस के Longसाथ Numberऔर Stringसाथ बदल Integer)। यह अभी तक एक और कारण बताता है कि आपको अपने वर्ग डिजाइन के लिए इस प्रकार के असफल व्यवहार पर भरोसा नहीं करना चाहिए, क्योंकि यहां संकलन करने में विफलता एक वांछनीय व्यवहार नहीं है।

अन्य 2 के लिए (और वास्तव में Consumerआपके द्वारा काम करने की इच्छा रखने वाले अन्य किसी भी इनवोकेशन के माध्यम से), व्यवहार स्पष्ट होना चाहिए यदि आप ऊपर दिए गए तरीकों में से एक के लिए निर्धारित प्रकार की प्रक्रिया के माध्यम से काम करते हैं (यानी with, पहले के लिए, withXके लिए तीसरे)। केवल एक छोटा सा बदलाव है, जिस पर आपको ध्यान देना चाहिए:

  • पहले पैरामीटर पर बाधा ( t::setNumber साथ संगत है Consumer<R> ) इसके बजाय कम हो जाएगी क्योंकि यह करता है । यह कमी पर जुड़े प्रलेखन में वर्णित है।R <: NumberNumber <: RSupplier<R>

मैं इसे उपरोक्त प्रक्रियाओं में से किसी एक के माध्यम से काम करने के लिए पाठक के लिए एक एक्सर्साइज़ के रूप में छोड़ता हूं, अतिरिक्त ज्ञान के इस टुकड़े से लैस, खुद को यह दिखाने के लिए कि वास्तव में एक विशेष आह्वान क्यों करता है या संकलन नहीं करता है।


बहुत गहराई से, अच्छी तरह से शोध और तैयार की गई। धन्यवाद!
ज़बुज़ार्ड

@ user31601 क्या आप ध्यान दिला सकते हैं कि आपूर्तिकर्ता से उपभोक्ता तक का अंतर क्या है। मैंने उसके लिए मूल प्रश्न में एक विस्तारित उदाहरण जोड़ा। यह letBe (), letBeX () और let () हो सकता है () () (आपूर्तिकर्ता) / उपभोक्ता के आधार पर विभिन्न संस्करण के लिए सहसंयोजक, विपरीत और अपरिवर्तनीय व्यवहार दिखाता है।
जूकी

@jukzi मैंने कुछ अतिरिक्त नोट्स जोड़े हैं, लेकिन आपके पास इन नए उदाहरणों के माध्यम से काम करने के लिए पर्याप्त जानकारी होनी चाहिए।
user31601

थॉट्स इंटरस्टिंग: 18.2.1 में इतने विशेष मामले। लंबोदर और विधि संदर्भों के लिए जहां मैंने अपनी भोली समझ से उनके लिए किसी विशेष मामले की उम्मीद नहीं की होगी। और शायद कोई भी सामान्य डेवलपर उम्मीद नहीं करेगा।
जूकी

खैर, मुझे लगता है कि इसका कारण यह है कि लैम्ब्डा और विधि संदर्भों के साथ, कंपाइलर को यह तय करने की जरूरत है कि लैम्बडा को किस प्रकार का कार्यान्वयन करना चाहिए - यह एक विकल्प बनाना है! उदाहरण के लिए, TypeInference::getLongनकल Supplier<Long>या Supplier<Serializable>या Supplier<Number>आदि, लेकिन महत्वपूर्ण रूप से यह केवल उनमें से एक को लागू कर सकता है (किसी भी अन्य वर्ग की तरह)! यह अन्य सभी अभिव्यक्तियों से अलग है, जहां कार्यान्वित प्रकार सभी सामने वाले को जानते हैं, और संकलक को बस काम करना पड़ता है कि क्या उनमें से कोई भी बाधा आवश्यकताओं को पूरा करता है।
user31601
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.