वैरिएबल की जाँच करने के लिए वैकल्पिक अधिमान्य का उपयोग क्यों किया जा रहा है?


25

दो कोड उदाहरण लें:

if(optional.isPresent()) {
    //do your thing
}

if(variable != null) {
    //do your thing
}

जहां तक ​​मैं सबसे स्पष्ट अंतर बता सकता हूं कि वैकल्पिक को एक अतिरिक्त ऑब्जेक्ट बनाने की आवश्यकता है।

हालाँकि, बहुत से लोग तेजी से ऑप्शनल को अपनाने लगे हैं। वैकल्पिक बनाम शून्य जांच का उपयोग करने का क्या फायदा है?


4
आप लगभग कभी isPresent उपयोग करना चाहते हैं, आप आमतौर पर ifPresent का उपयोग करना चाहिए या नक्शा
जे।

6
@jk। क्योंकि ifबयान पिछले दशक के sooooo हैं , और हर किसी का उपयोग अबाध सार और lambdas है।
user253751

2
@ मिनीबिस I ने एक बार दूसरे उपयोगकर्ता के साथ इस विषय पर एक लंबी बहस की थी। मुद्दा यह है कि if(x.isPresent) fails_on_null(x.get)आप टाइप सिस्टम से बाहर निकलते हैं और यह शर्त रखनी होती है कि कोड शर्त (फंक्शन कॉल) के बीच (सम्मिलित रूप से छोटी) दूरी पर "आपके सिर में" नहीं फटेगा। में optional.ifPresent(fails_on_null)प्रकार प्रणाली आप के लिए यह गारंटी नहीं देता है, और आपको चिंता करने की जरूरत नहीं है।
जिग्गीस्टार

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

जवाबों:


19

Optionalकाम करने के लिए उस प्रकार की प्रणाली का उपयोग करता है जिसे आपको अन्यथा अपने सिर में करना होगा: यह याद रखना कि दिया गया संदर्भ हो सकता है या नहीं null। यह अच्छा है। कंपाइलर को बोरिंग ड्रगवर्क को संभालने देना और रचनात्मक, दिलचस्प काम के लिए मानव विचार को आरक्षित रखने के लिए हमेशा स्मार्ट होना चाहिए।

बिना Optional, आपके कोड में हर संदर्भ एक अस्पष्टीकृत बम की तरह है। इसे एक्सेस करना कुछ उपयोगी हो सकता है, अन्यथा यह आपके प्रोग्राम को अपवाद के रूप में समाप्त कर सकता है।

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

दुर्भाग्य से, अब जो अधिकांश भाषाएं प्रदान करती Optionalहैं, वे समाप्त नहीं हुई हैं null, इसलिए आप "बिल्कुल नहीं null, कभी" की एक सख्त नीति बनाकर केवल अवधारणा से लाभ प्राप्त कर सकते हैं । इसलिए, Optionalउदाहरण के लिए जावा को उतने सम्मोहक नहीं होना चाहिए जितना कि आदर्श रूप में होना चाहिए।


चूँकि आपका उत्तर सबसे ऊपर है, यह एक लाभ के रूप में लम्बदा के उपयोग को जोड़ने के लायक हो सकता है - भविष्य में इसे पढ़ने वाले किसी व्यक्ति के लिए (मेरा उत्तर देखें)
विलियम डन

अधिकांश आधुनिक भाषाएँ गैर-अशक्त प्रकार, कोटलिन, टाइपस्क्रिप्ट, AFAIK प्रदान करती हैं।
ज़ेन

5
IMO यह एक @ एन्यूलेबल एनोटेशन के साथ बेहतर है। Optionalसिर्फ आपको यह याद दिलाने के लिए उपयोग करने का कोई कारण नहीं है कि मूल्य शून्य हो सकता है
हिल्किकस

18

एक Optionalसंचालन में मजबूत टाइपिंग लाता है जो विफल हो सकता है, जैसा कि अन्य उत्तर कवर किए गए हैं, लेकिन वह सबसे दिलचस्प या मूल्यवान चीज से बहुत दूर Optionalsहै जो तालिका में लाती है। बहुत अधिक उपयोगी विफलता के लिए जाँच में देरी या बचने की क्षमता है, और आसानी से विफल हो सकने वाले कई ऑपरेशनों की रचना करना है।

विचार करें कि क्या आपके पास आपके optionalउदाहरण कोड से चर था , तो आपको दो अतिरिक्त चरणों का प्रदर्शन करना होगा जो प्रत्येक संभावित रूप से विफल हो सकते हैं। यदि रास्ते में कोई भी कदम विफल होता है, तो आप इसके बजाय एक डिफ़ॉल्ट मान लौटना चाहते हैं। Optionalsसही तरीके से उपयोग करने पर , आप कुछ इस तरह से समाप्त करते हैं:

return optional.flatMap(x -> x.anotherOptionalStep())
               .flatMap(x -> x.yetAnotherOptionalStep())
               .orElse(defaultValue);

साथ nullमैं के लिए तीन बार जांच करने के लिए पड़ता था nullइससे पहले कार्यवाही, जो कोड के लिए जटिलता और रखरखाव सिर दर्द का एक बहुत कुछ कहते हैं। कार्य और कार्यों के Optionalsलिए बनाया गया है कि जाँच करें ।flatMaporElse

नोट मैंने isPresentएक बार कॉल नहीं किया था , जिसे आपको उपयोग करते समय एक कोड गंध के रूप में सोचना चाहिए Optionals। इसका मतलब यह नहीं है कि आपको कभी भी उपयोग नहीं करना चाहिए isPresent, बस आपको किसी भी कोड की भारी छानबीन करनी चाहिए, यह देखने के लिए कि क्या कोई बेहतर तरीका है। अन्यथा, आप सही हैं, आप केवल एक सीमांत प्रकार का सुरक्षा लाभ प्राप्त कर रहे हैं null

यह भी ध्यान दें कि मैं अपने कोड के अन्य भागों को मध्यवर्ती परिणामों से बचाने के लिए, इन सभी को एक फ़ंक्शन में संलग्न करने के बारे में चिंतित नहीं हूं। यदि यह .orElse(defaultValue)उदाहरण के लिए किसी अन्य फ़ंक्शन में मेरे लिए अधिक समझ में आता है , तो मुझे इसे वहां रखने के बारे में बहुत कम योग्यताएं हैं, और आवश्यकतानुसार विभिन्न कार्यों के बीच संचालन की रचना करना बहुत आसान है।


10

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

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


4

मैं आपको एक उदाहरण देता हूं:

class UserRepository {
     User findById(long id);
}

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

दूसरा उदाहरण:

class UserRepository {
     Optional<User> findById(long id);
}

अब, यहाँ क्या होता है अगर कोई यूजर आईडी नहीं है? सही, आपको Optional.absent () उदाहरण मिलता है और आप इसे Optional.isPresent () के साथ देख सकते हैं। वैकल्पिक के साथ विधि हस्ताक्षर इसके अनुबंध के बारे में अधिक स्पष्ट है। यह तुरंत स्पष्ट है, कि विधि को कैसे व्यवहार करना है।

क्लाइंट कोड पढ़ते समय इसका लाभ भी होता है:

User user = userRepository.findById(userId).get();

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

वैकल्पिक का उपयोग उस कन्वेंशन के साथ किया जाता है जो रिटर्न प्रकार के साथ तरीके वैकल्पिक कभी वापस नहीं आते हैं और आमतौर पर वैकल्पिक रिटर्न प्रकार के बिना (कम मजबूत) कन्वेंशन के साथ विधि कभी भी वापस नहीं आती है (लेकिन यह @Nonnull, @NotNull या इसी तरह के साथ एनोटेट करना बेहतर है) ।


3

एक Optional<T>आप "विफलता" या "नहीं परिणाम" अपने तरीकों के लिए एक वैध प्रतिक्रिया / वापसी मान के रूप में (लगता है, जैसे, एक डेटाबेस देखने के) की अनुमति देता है। एक का उपयोग करना Optionalउपयोग करने के बजाए nullविफलता का संकेत करने के लिए / कोई परिणाम कुछ लाभ हैं:

  • यह स्पष्ट रूप से संपर्क करता है कि "विफलता" है एक विकल्प। आपकी विधि के उपयोगकर्ता को यह अनुमान लगाने की आवश्यकता नहीं है कि क्या nullवापस किया जा सकता है।
  • मूल्य null, कम से कम मेरी राय में, कुछ भी इंगित करने के लिए उपयोग नहीं किया जाना चाहिए क्योंकि शब्दार्थ पूरी तरह से स्पष्ट नहीं हो सकता है। इसका उपयोग कचरा संग्रहकर्ता को यह बताने के लिए किया जाना चाहिए कि पहले संदर्भित ऑब्जेक्ट एकत्र किया जा सकता है।
  • Optionalवर्ग सशर्त मूल्यों के साथ काम करने के लिए कई अच्छे तरीके प्रदान (जैसे, ifPresent()) या एक पारदर्शी तरीके से डिफ़ॉल्ट मान परिभाषित ( orElse())।

दुर्भाग्य से, यह nullकोड में चेक की आवश्यकता को पूरी तरह से नहीं हटाता है क्योंकि Optionalऑब्जेक्ट स्वयं अभी भी हो सकता है null


4
यह वास्तव में क्या वैकल्पिक नहीं है। किसी त्रुटि की रिपोर्ट करने के लिए, एक अपवाद का उपयोग करें। आप ऐसा नहीं कर सकते हैं, तो एक प्रकार है जो होता है का उपयोग या तो एक परिणाम या एक त्रुटि कोड
जेम्स यंगमैन

मैं दृढ़ता से असहमत हूँ। Optional.empty () मेरी राय में विफलता या गैर-अस्तित्व दिखाने का एक शानदार तरीका है।
लीजेंडलक्विटी

@ लेग्लेन्डलेंथ, मुझे विफलता के मामले में दृढ़ता से असहमत होना चाहिए। यदि कोई फ़ंक्शन विफल हो जाता है, तो यह मुझे एक स्पष्टीकरण दे सकता है, न कि केवल एक खाली, "मैं विफल"
विंस्टन एवर्ट

क्षमा करें, मैं सहमत हूं, जिसका अर्थ है 'अपेक्षित विफलता', जैसा कि खोज के दौरान 'x' नाम के कर्मचारी को नहीं मिलता है।
लीजेंडल्रिक्स

3

अन्य उत्तरों के अलावा, जब क्लीन कोड लिखने की बात आती है तो ऑप्शनल का दूसरा बड़ा फायदा यह है कि आप इस घटना में एक लैम्ब्डा एक्सप्रेशन का उपयोग कर सकते हैं, जो कि मूल्य में मौजूद है, जैसा कि नीचे दिखाया गया है:

opTr.ifPresent(tr -> transactions.put(tr.getTxid(), tr));

2

निम्नलिखित विधि पर विचार करें:

void dance(Person partner)

अब कुछ कॉलिंग कोड देखें:

dance(null);

इससे दुर्घटना को कहीं और ट्रैक करना मुश्किल हो जाता है, क्योंकि danceअशक्त होने की उम्मीद नहीं थी।

dance(optionalPerson)

यह एक संकलित त्रुटि का कारण बनता है, क्योंकि नृत्य एक उम्मीद Personनहीं कर रहा थाOptional<Person>

dance(optionalPerson.get())

अगर मेरे पास कोई व्यक्ति नहीं था, तो इस लाइन पर एक अपवाद का कारण बनता है, उस बिंदु पर जहां मैंने अवैध रूप Optional<Person>से एक व्यक्ति में बदलने की कोशिश की । कुंजी यह है कि एक अशक्त गुजरने के विपरीत, यहां निशान को छोड़कर, कार्यक्रम में कुछ अन्य स्थान नहीं।

इसे सभी को एक साथ रखने के लिए: वैकल्पिक दुरुपयोग का उपयोग समस्याओं को ट्रैक करने में आसान होता है, अशक्त दुरुपयोग का कारण समस्याओं को ट्रैक करना मुश्किल होता है।


1
यदि आप Optional.get()अपने कोड को कॉल करते समय अपवादों को फेंक रहे हैं, तो आप बुरी तरह से लिखे गए हैं - आपको Optional.isPresent()पहले जाँच किए बिना लगभग Optional.get को कॉल नहीं करना चाहिए (जैसा कि ओपी में संकेत दिया गया है) या आप लिख सकते हैं optionalPersion.ifPresent(myObj::dance)
क्रिस कूपर

@QmunkE, हाँ, आपको केवल Optional.get () कॉल करना चाहिए, यदि आप पहले से ही जानते हैं कि वैकल्पिक खाली नहीं है (या तो क्योंकि आप इसेPresent कहते हैं या क्योंकि आपका एल्गोरिथ्म इसकी गारंटी देता है)। हालाँकि, मुझे इस बात की चिंता है कि लोग नेत्रहीन जाँच कर रहे हैं। यह अनुपस्थित है और फिर अनुपस्थित मूल्यों की अनदेखी करने से मूक विफलताओं का एक मेजबान बन जाता है जो ट्रेस करने के लिए एक दर्द होगा।
विंस्टन ईवर्ट

1
मुझे अल्टरनेटिव्स पसंद हैं। लेकिन मैं कहूंगा कि सादे पुराने अशक्त संकेत वास्तविक दुनिया कोड में शायद ही कभी एक समस्या है। वे लगभग हमेशा कोड की अपमानजनक रेखा के पास विफल होते हैं। और मुझे लगता है कि इस विषय के बारे में बात करने पर लोगों को बहुत खुशी मिलती है।
लीजेंड लैंथ

@LegendLength, मेरा अनुभव है कि 95% मामले वास्तव में आसानी से पता लगाने योग्य होते हैं कि NULL कहां से आता है। हालांकि, शेष 5% को ट्रैक करना बेहद मुश्किल है।
विंस्टन इवर्ट

-1

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

if (variable != nil) {
    [variable doThing];
}

उपरोक्त जैसा कोड ऑब्जेक्टिव-सी में अनसुना है। इसके बजाय, प्रोग्रामर सिर्फ:

[variable doThing];

यदि variableकोई मान शामिल है, तो doThingउस पर कॉल किया जाएगा। यदि नहीं, तो कोई नुकसान नहीं। कार्यक्रम इसे नो-ऑप के रूप में मानेगा और चालू रहेगा।

यह वैकल्पिक का वास्तविक लाभ है। आपको अपना कोड नहीं देना होगा if (obj != nil)


क्या यह चुपचाप असफल होने का एक रूप नहीं है? कुछ मामलों में आप परवाह कर सकते हैं कि मूल्य शून्य है, और इसके बारे में कुछ करना चाहते हैं।
लीजेंडल्रिक्सल

-3

अगर (वैकल्पिक।) () {

यहाँ स्पष्ट समस्या यह है कि यदि "वैकल्पिक" वास्तव में गायब है (यानी शून्य है) तो आपका कोड NullReferenceException (या समान) के साथ उड़ने वाला है, जो किसी भी विधि को एक अशक्त वस्तु संदर्भ में कॉल करने का प्रयास कर रहा है!

आप एक स्टैटिक, हेल्पर-क्लास विधि लिखना चाहते हैं जो किसी भी प्रकार के ऑब्जेक्ट के अशक्तता को निर्धारित करता है, कुछ इस प्रकार है:

function isNull( object o ) 
{
   return ( null == o ); 
}

if ( isNull( optional ) ) ... 

या, शायद, अधिक उपयोगी:

function isNotNull( object o ) 
{
   return ( null != o ); 
}

if ( isNotNull( optional ) ) ... 

लेकिन क्या इनमें से कोई भी वास्तव में मूल से अधिक पठनीय / समझने योग्य / बनाए रखने योग्य है?

if ( null == optional ) ... 
if ( null != optional ) ... 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.