लंबोदर अभिव्यक्ति में प्रयुक्त चर अंतिम या प्रभावी रूप से अंतिम होना चाहिए


134

लंबोदर अभिव्यक्ति में प्रयुक्त चर अंतिम या प्रभावी रूप से अंतिम होना चाहिए

जब मैं calTzइसका उपयोग करने की कोशिश करता हूं तो यह त्रुटि दिखाई दे रही है।

private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
    try {
        cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
            VTimeZone v = (VTimeZone) component;
            v.getTimeZoneId();
            if (calTz == null) {
                calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
            }
        });
    } catch (Exception e) {
        log.warn("Unable to determine ical timezone", e);
    }
    return null;
}

5
आप calTzलंबोदर से संशोधित नहीं कर सकते ।
इलियट फ्रिश

2
मुझे लगता है कि यह उन चीजों में से एक था जो सिर्फ जावा 8 के लिए समय पर नहीं किया गया था। लेकिन जावा 8 2014 था। स्काला और कोटलिन ने इसे वर्षों के लिए अनुमति दी है, इसलिए यह स्पष्ट रूप से संभव है। क्या जावा कभी इस अजीब प्रतिबंध को खत्म करने की योजना बना रहा है?
ग्लेनपेटर्सन

5
यहाँ @MSDousti की टिप्पणी का अद्यतन लिंक है।
geisterfurz007

मुझे लगता है कि आप वर्कअराउंड के रूप में कंप्लीटेबल फ्यूचर्स का उपयोग कर सकते हैं।
क्रालैन

एक महत्वपूर्ण बात जो मैंने देखी - आप सामान्य चर के बजाय स्थैतिक चर का उपयोग कर सकते हैं (यह प्रभावी रूप से अंतिम रूप से मुझे लगता है)
कौशलपर्व

जवाबों:


68

एक finalचर का मतलब है कि यह केवल एक बार त्वरित किया जा सकता है। जावा में आप लैम्ब्डा के साथ-साथ अनाम आंतरिक कक्षाओं में गैर-अंतिम चर का उपयोग नहीं कर सकते हैं।

आप अपने कोड को पुराने प्रत्येक लूप के साथ रिफलेक्टर कर सकते हैं:

private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
    try {
        for(Component component : cal.getComponents().getComponents("VTIMEZONE")) {
        VTimeZone v = (VTimeZone) component;
           v.getTimeZoneId();
           if(calTz==null) {
               calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
           }
        }
    } catch (Exception e) {
        log.warn("Unable to determine ical timezone", e);
    }
    return null;
}

भले ही मुझे इस कोड के कुछ टुकड़ों का बोध न हो:

  • आप v.getTimeZoneId();इसके रिटर्न मान का उपयोग किए बिना कॉल करते हैं
  • असाइनमेंट के साथ calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());आप मूल रूप से उत्तीर्ण calTzनहीं होते हैं और आप इस पद्धति में इसका उपयोग नहीं करते हैं
  • आप हमेशा लौटते हैं null, आप voidरिटर्न प्रकार के रूप में सेट क्यों नहीं करते हैं ?

आशा है कि ये सुझाव भी आपको बेहतर बनाने में मदद करेंगे।


हम गैर अंतिम स्थैतिक चर का उपयोग कर सकते हैं
नरेंद्र जग्गी

93

यद्यपि अन्य उत्तर आवश्यकता को सिद्ध करते हैं, वे यह नहीं समझाते हैं कि आवश्यकता क्यों मौजूद है।

JLS का उल्लेख है कि .215.27.2 में क्यों :

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

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


11
अच्छा उत्तर +1, और मुझे आश्चर्य है कि कम कवरेज के कारण प्रभावी रूप से फाइनल होने के लिए क्या लगता है। ध्यान दें: एक स्थानीय चर केवल एक लैम्ब्डा द्वारा कब्जा किया जा सकता है अगर यह है भी निश्चित रूप से लैम्ब्डा के शरीर से पहले सौंपा। दोनों आवश्यकताओं को यह सुनिश्चित करने के लिए प्रतीत होता है कि स्थानीय चर तक पहुंच थ्रेड सुरक्षित होगा।
टिम बैजलेसेन

2
कोई भी विचार क्यों यह केवल स्थानीय चर तक ही सीमित है, और वर्ग के सदस्यों के लिए नहीं? मैं खुद को अक्सर एक वर्ग के सदस्य के रूप में अपने चर को घोषित करके समस्या को दरकिनार करता हूं ...
डेविड रेफेली

4
@DavidRefaeli स्मृति मॉडल से वर्ग के सदस्य कवर / प्रभावित होते हैं, जिनका यदि पालन किया जाता है, तो साझा किए जाने पर अनुमानित परिणाम प्राप्त होंगे। स्थानीय चर नहीं हैं, जैसा कि ables17.4.1
डाइऑक्सिन

यह एक मूर्खतापूर्ण हैक है, जिसे हटाया जाना चाहिए। कंपाइलर को संभावित क्रॉस-थ्रेड वैरिएबल एक्सेस के बारे में चेतावनी देनी चाहिए, लेकिन इसकी अनुमति देनी चाहिए। या, यह जानने के लिए पर्याप्त स्मार्ट होना चाहिए कि क्या आपका लैम्ब्डा एक ही धागे पर चल रहा है, या समानांतर में चल रहा है, आदि यह एक मूर्खतापूर्ण सीमा है, जो मुझे दुखी करता है। और जैसा कि अन्य ने उल्लेख किया है, जैसे कि C # में समस्याएँ मौजूद नहीं हैं।
जोश एम।

@JoshM। C # भी आपको परिवर्तनशील मूल्य प्रकार बनाने की अनुमति देता है , जिसे लोग मुद्दों को रोकने के लिए टालने की सलाह देते हैं। इस तरह के सिद्धांत होने के बजाय, जावा ने इसे पूरी तरह से रोकने का फैसला किया। यह लचीलेपन की कीमत पर, उपयोगकर्ता की त्रुटि को कम करता है। मैं इस प्रतिबंध से सहमत नहीं हूं, लेकिन यह उचित है। समानता के लिए लेखांकन को संकलक के अंत में कुछ अतिरिक्त काम करने की आवश्यकता होती है, यही कारण है कि " चेतावनी क्रॉस-थ्रेडेड एक्सेस " का मार्ग नहीं लिया गया था। ऐनक पर काम करने वाला डेवलपर शायद इसके लिए हमारी एकमात्र पुष्टि होगा।
डाइऑक्सिन

59

एक लंबोदर से, आपको ऐसी किसी भी चीज़ का संदर्भ नहीं मिल सकता है जो अंतिम नहीं है। आपको अपने वैरिएबल को रखने के लिए लैमडा के बाहर से एक अंतिम आवरण घोषित करने की आवश्यकता है।

मैंने इस रैपर के रूप में अंतिम 'संदर्भ' ऑब्जेक्ट जोड़ा है।

private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
    final AtomicReference<TimeZone> reference = new AtomicReference<>();

    try {
       cal.getComponents().getComponents("VTIMEZONE").forEach(component->{
        VTimeZone v = (VTimeZone) component;
           v.getTimeZoneId();
           if(reference.get()==null) {
               reference.set(TimeZone.getTimeZone(v.getTimeZoneId().getValue()));
           }
           });
    } catch (Exception e) {
        //log.warn("Unable to determine ical timezone", e);
    }
    return reference.get();
}   

मैं उसी या इसी तरह के दृष्टिकोण के बारे में सोच रहा था - लेकिन मैं इस जवाब पर कुछ विशेषज्ञ सलाह / प्रतिक्रिया देखना चाहूंगा?
योयो

4
यह कोड एक प्रारंभिक याद करता है reference.set(calTz);या संदर्भ का उपयोग करके बनाया जाना चाहिए new AtomicReference<>(calTz), अन्यथा पैरामीटर के रूप में प्रदान किया गया गैर-शून्य TimeZone खो जाएगा।
जुलिएन क्रोनग

8
यह पहला उत्तर होना चाहिए। एक AtomicReference (या समान Atomic___ वर्ग) हर संभव परिस्थिति में सुरक्षित रूप से इस सीमा के आसपास काम करता है।
GlenPeterson

1
सहमत, यह स्वीकृत उत्तर होना चाहिए। अन्य उत्तर एक गैर-कार्यात्मक प्रोग्रामिंग मॉडल पर वापस गिरने के बारे में उपयोगी जानकारी देते हैं, और ऐसा क्यों किया गया था, लेकिन वास्तव में आपको समस्या के आसपास काम करने का तरीका नहीं बताते हैं!
जोनाथन बेन्

2
@GlenPeterson और एक भयानक निर्णय भी है, न केवल यह इस तरह से बहुत धीमा है, लेकिन आप साइड-इफेक्ट्स प्रॉपर्टी को अनदेखा भी कर रहे हैं जो प्रलेखन को अनिवार्य करता है।
यूजीन

41

जावा 8 में एक नई अवधारणा है जिसे "प्रभावी रूप से अंतिम" चर कहा जाता है। इसका अर्थ है कि एक गैर-अंतिम स्थानीय चर जिसका मूल्य आरंभिकता के बाद कभी नहीं बदलता है, "प्रभावी रूप से अंतिम" कहलाता है।

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

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

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

मुझे यहां एक अच्छी व्याख्या मिली


कोड स्वरूपण केवल कोड के लिए उपयोग किया जाना चाहिए , न कि तकनीकी शब्दों के लिए। effectively finalकोड नहीं है, यह शब्दावली है। देखें कि गैर-कोड पाठ के लिए कोड स्वरूपण का उपयोग कब किया जाना चाहिए? पर मेटा स्टैक ओवरफ़्लो
चार्ल्स डफी

(तो " finalकीवर्ड" कोड का एक शब्द है और उस तरह से प्रारूपित करने के लिए सही है, लेकिन जब आप कोड के बजाय "अंतिम" का उपयोग विवरणात्मक रूप से करते हैं, तो यह इसके बजाय शब्दावली है)।
चार्ल्स डफी

9

अपने उदाहरण में, आप forEachएक साधारण forलूप के साथ लाम्डा को बदल सकते हैं और किसी भी चर को स्वतंत्र रूप से संशोधित कर सकते हैं । या, शायद, अपने कोड को फिर से फ़िल्टर करें ताकि आपको किसी भी चर को संशोधित करने की आवश्यकता न हो। हालांकि, मैं पूर्णता के लिए समझाता हूं कि त्रुटि का क्या मतलब है और इसके चारों ओर कैसे काम करना है।

जावा 8 भाषा विशिष्टता, .215.27.2 :

किसी भी स्थानीय चर, औपचारिक पैरामीटर, या अपवाद पैरामीटर का उपयोग किया जाता है, लेकिन लैम्ब्डा अभिव्यक्ति में घोषित नहीं किया जाना चाहिए या तो अंतिम रूप से घोषित किया जाना चाहिए या प्रभावी रूप से अंतिम ( final4.12.4 ), या एक संकलन-समय त्रुटि होती है जहां उपयोग का प्रयास किया जाता है।

मूल रूप से आप calTzएक लैम्बडा (या एक स्थानीय / अनाम वर्ग) के भीतर से एक स्थानीय चर ( इस मामले में) को संशोधित नहीं कर सकते । जावा में इसे प्राप्त करने के लिए, आपको एक उत्परिवर्तित वस्तु का उपयोग करना होगा और इसे (अंतिम चर के माध्यम से) लंबोदर से संशोधित करना होगा। यहाँ एक परिवर्तनशील वस्तु का एक उदाहरण एक तत्व का एक सरणी होगा:

private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
    TimeZone[] result = { null };
    try {
        cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
            ...
            result[0] = ...;
            ...
        }
    } catch (Exception e) {
        log.warn("Unable to determine ical timezone", e);
    }
    return result[0];
}

एक अन्य तरीका किसी वस्तु के क्षेत्र का उपयोग करना है। जैसे MyObj परिणाम = new MyObj (); ...; result.timeZone = ...; ....; वापसी परिणाम। समयक्षेत्र; हालांकि, ध्यान दें, जैसा कि ऊपर बताया गया है, यह आपको थ्रेड-सुरक्षा समस्याओं के लिए उजागर करता है। देखें stackoverflow.com/a/50341404/7092558
गिब्ज़िन्यू नु

0

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


0

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

private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
    try {
        TimeZone calTzLocal[] = new TimeZone[1];
        calTzLocal[0] = calTz;
        cal.getComponents().get("VTIMEZONE").forEach(component -> {
            TimeZone v = component;
            v.getTimeZoneId();
            if (calTzLocal[0] == null) {
                calTzLocal[0] = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
            }
        });
    } catch (Exception e) {
        log.warn("Unable to determine ical timezone", e);
    }
    return null;
}

यह अलेक्जेंडर उडालोव के सुझाव के समान है। इसके अलावा मुझे लगता है कि यह दृष्टिकोण दुष्प्रभावों पर निर्भर है।
स्क्रेप्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.