java जावा लैम्ब्डास में अनोखी आंतरिक कक्षाओं की तुलना में अलग-अलग वैरिएबल आवश्यकताएं हैं




lambda anonymous-inner-class (2)

यह संकलित नहीं होगा:

public class Example
{
  private final int x;
  private final int y = 2 * x;

  public Example() {
    x = 10;
  }
}

लेकिन यह होगा:

public class Example
{
  private final int x;
  private final int y;

  public Example() {
    x = 10;
    y = 2 * x;
  }
}

और ऐसा होगा:

public class Example
{
  private final int x = 10;
  private final int y = 2 * x;
}

तो यह लम्ब्दास के साथ कुछ नहीं करना है कन्स्ट्रक्टर निष्पादित होने से पहले उस फील्ड पर आरंभ किया गया है जो इसे उसी लाइन पर आरंभीकृत किया गया है जिसे उस पर घोषित किया गया है। इसलिए उस बिंदु पर, चर 'वैल' (या इस उदाहरण 'x' में) को आरम्भ नहीं किया गया है।

मेरे पास एक गुमनाम आंतरिक वर्ग और एक समान लैम्ब्डा है क्यों लैम्ब्डा के लिए चर प्रारंभिक नियम कठोर हैं, और क्या एक अनाम आंतरिक वर्ग की तुलना में एक समाधान क्लीनर है या कन्स्ट्रक्टर में इसे आरंभ करना है?

import java.util.concurrent.Callable;

public class Immutable {
    private final int val;

    public Immutable(int val) { this.val = val; }

    // Works fine
    private final Callable<String> anonInnerGetValString = new Callable<String>() {    
        @Override
        public String call() throws Exception {
            return String.valueOf(val);
        }
    };

    // Doesn't compile; "Variable 'val' might not have been initialized"
    private final Callable<String> lambdaGetValString = () -> String.valueOf(val);
}

संपादित करें: मैंने एक वैकल्पिक हल में भाग लिया था: val लिए एक गेटर का उपयोग करना।


लैम्ब्डा अभिव्यक्ति निकायों के बारे में अध्याय बताता है

अज्ञात वर्ग घोषणाओं में प्रदर्शित होने वाले कोड के विपरीत, लैम्ब्डा शरीर में नाम और this और super कीवर्ड संदर्भित घोषणाओं की पहुंच के साथ-साथ आसपास के संदर्भ में समान होते हैं (लैंबडा मापदंडों को छोड़कर नए नाम शामिल करते हुए)।

लैम्ब्डा अभिव्यक्ति के शरीर में this (स्पष्ट और अंतर्निहित दोनों) की पारदर्शिता - यही है, इसे आस-पास के संदर्भों के समान ही माना जाता है - कार्यान्वयन के लिए अधिक लचीलेपन की अनुमति देता है, और शरीर में अयोग्य नामों का अर्थ निर्भर होने से रोकता है ओवरलोड संकल्प पर

वे उस वजह से अधिक सख्त हैं

आसपास के प्रसंग, इस मामले में, एक क्षेत्र के लिए एक असाइनमेंट है और हाथ में समस्या अभिव्यक्ति के दाहिनी ओर फ़ील्ड, val , रिक्त final फ़ील्ड की final

जावा भाषा विशिष्टता बताती है

प्रत्येक लोकल वैरिएबल (§14.4) और प्रत्येक रिक्त final क्षेत्र (§4.12.4, §8.3.1.2) का निश्चित रूप से असाइन किया हुआ मान होना चाहिए जब इसके मूल्य का कोई भी उपयोग होता है।

इसके मूल्य के लिए उपयोग में एक साधारण अभिव्यक्ति में कहीं भी होती है (या, फ़ील्ड के लिए, फ़ील्ड के लिए सरल नाम), सरल कार्य का ऑपरेटर = (§ 15.26.1)।

किसी स्थानीय चर या रिक्त final क्षेत्र x के प्रत्येक एक्सेस के लिए x निश्चित रूप से पहुंच से पहले अवश्य सौंपा जाना चाहिए, या एक संकलन-समय त्रुटि उत्पन्न होती है।

यह तो कहने पर चला जाता है

चलो एक कक्षा हो, और C रिक्त final गैर के एक static सदस्य क्षेत्र, C में घोषित करें। फिर:

  • V निश्चित रूप से अनअसाइन्ड (और इसके निश्चित रूप से निश्चित रूप से निर्दिष्ट नहीं है) बाएंस्ट्रीम इनिशियलाइज़र इनिशियलाइज़र (§8.6) से पहले या C उदाहरण चर प्रारंभिक

  • V [संयुक्त राष्ट्र] उदाहरण आवंटितकर्ता से पहले सौंपा गया है, उदाहरण के बावजूद IF V अलावा अन्य C उदाहरण चर initializer C [पूर्व] उदाहरण के प्रारंभिक उदाहरण प्रारंभकर्ता या C आवृत्ति चर initializer के बाद सौंपा गया C

आपका कोड मूल रूप से इस तरह दिखता है

private final int val;
// leftmost instance variable initializer, val still unassigned 
private final Callable<String> anonInnerGetValString = ...
// still unassigned after preceding variable initializer
private final Callable<String> lambdaGetValString = ...

कंपाइलर इसलिए निर्धारित करता है कि जब यह lambdaGetValString लिए lambdaGetValString अभिव्यक्ति के भीतर पहुंच हो, तो उसे अनअसाइन किए गए में val

ऊपर दिए गए नियम एक साधारण नाम, val , एक योग्य अभिव्यक्ति के लिए, this.val के उपयोग के लिए लागू होते हैं। आप उपयोग कर सकते हैं

final Callable<String> lambdaGetValString = () -> String.valueOf(this.val);




anonymous-inner-class