क्या है अमरूद की ऑप्शनल क्लास की बात


89

मैंने हाल ही में इसके बारे में पढ़ा है और इस वर्ग का उपयोग करते हुए लोगों को देखा है, लेकिन बहुत अधिक मामलों में, उपयोग करने के nullसाथ-साथ काम किया है - यदि अधिक सहज रूप से नहीं। क्या कोई ऐसा ठोस उदाहरण प्रदान कर सकता Optionalहै, जो कुछ ऐसा हासिल कर nullसकता है जो अधिक क्लीनर तरीके से नहीं कर सकता है? केवल एक चीज जिसके बारे में मैं सोच सकता हूं, वह यह है Mapsकि इसके साथ nullकुंजियों को स्वीकार न करें, लेकिन यहां तक ​​कि नल के मूल्य के एक पक्ष "मैपिंग" के साथ भी किया जा सकता है। क्या कोई मुझे अधिक ठोस तर्क प्रदान कर सकता है? धन्यवाद।


12
यादृच्छिक शेख़ी: मैं इसे नफरत करता हूं जब लोग "पैटर्न" का उपयोग करते हैं और कोड को कुछ सैद्धांतिक लाभ के लिए बहुत बदसूरत बनाते हैं जो मौजूद नहीं है ...
RAY

Java8 के अनुसार, मैं अब इस Guava क्लास का उपयोग नहीं करूंगा क्योंकि यह JDK से कम शक्तिशाली है। देखें stackoverflow.com/a/10756992/82609
सेबेस्टियन Lorber

जवाबों:


155

अमरूद टीम के सदस्य यहां।

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

लेकिन मैं कहूंगा कि Optionalपठनीयता में सबसे बड़ा फायदा यह नहीं है: फायदा इसके बेवकूफ-प्रूफ-नेस का है। यह आपको अनुपस्थित मामले के बारे में सक्रिय रूप से सोचने के लिए मजबूर करता है यदि आप चाहते हैं कि आपका कार्यक्रम सभी को संकलित करें, क्योंकि आपको Optionalउस मामले को सक्रिय रूप से खोलना और संबोधित करना है। अशक्त चीजों को आसानी से भूल जाना आसान बनाता है, और हालांकि FindBugs मदद करता है, मुझे नहीं लगता कि यह लगभग इस मुद्दे को भी संबोधित करता है। यह विशेष रूप से प्रासंगिक है जब आप उन मूल्यों को वापस कर रहे हैं जो "वर्तमान" हो सकते हैं या नहीं हो सकते हैं। आप (और अन्य) यह भूल जाने की अधिक संभावना है कि आप मूल्य other.method(a, b)को वापस कर सकते हैं nullजितना कि आप भूल aसकते हैं कि nullजब आप लागू कर रहे हैं तो यह हो सकता है other.method। रिटर्निंगOptional इससे कॉल करने वालों के लिए उस मामले को भूलना असंभव हो जाता है, क्योंकि उन्हें स्वयं वस्तु को खोलना होता है।

इन कारणों के लिए, हम अनुशंसा करते हैं कि आप Optionalअपने तरीकों के लिए एक वापसी प्रकार के रूप में उपयोग करें, लेकिन जरूरी नहीं कि आपके विधि तर्कों में हो।

(यह पूरी तरह से, इस तरह से चर्चा से घूस है ।)


3
एक महान विवरण के लिए +1। मुझे नहीं पता कि यह प्रेरणा है, लेकिन मैं SML, OCaml, और F # में विकल्प प्रकारों के लिए एक सूचक जोड़ूंगा, जिसमें एक ही शब्दार्थ है।
एडम मिहलसिन

2
हमेशा किसी ऐसे व्यक्ति से जवाब पाने के लिए जो सीधे तौर पर शामिल था। मेरे पास उसके लिए + 1 +1 था। एक महान जवाब के लिए +1 और चाहेंगे। (लेकिन मैं नहीं कर सकता।) मुझे लगता है कि यह एक अपरिचित विधि के उपभोक्ताओं को यह मानने के लिए मजबूर करने के लिए रिटर्न वैल्यू के रूप में है कि एक "कुछ भी" नहीं लौटाया जा सकता है, एक सम्मोहक कारण है। मुझे पसंद नहीं है, हालांकि यह कैसे अधिक उपयोग किया जा रहा है (या यहां तक ​​कि दुर्व्यवहार किया गया है)। उदाहरण के लिए, मैं वास्तव में असहज महसूस करता हूं जब लोग ऑप्शंस को मैप्स में मान के रूप में देखते हैं। गैर-मौजूद / अप्रयुक्त कुंजी के लिए मानचित्र को बनाए रखने वाला नक्शा एक अच्छी तरह से स्थापित प्रतिमान है ... इसे और अधिक जटिल बनाने की आवश्यकता नहीं ...
RAY

9
यह अच्छी तरह से स्थापित है कि अगर कोई कुंजी अनमैप्ड है तो Mapवापस लौटता nullहै, लेकिन याद रखें कि यदि आप करते हैं map.put(key, null), तो map.containsKey(key)वापस आ जाएगा trueलेकिन map.get(key)वापस आ जाएगा nullOptional"स्पष्ट रूप से नल करने के लिए मैप किया गया" मामले और "मैप के मामले में मौजूद नहीं" के बीच अंतर को साफ करने में आसान हो सकता है। मैं वह अनुदान दूंगा Optionalजिसका दुरुपयोग किया जा सकता है, लेकिन मैं अभी तक आश्वस्त नहीं हूं कि आपके द्वारा वर्णित मामला दुरुपयोग है।
लुई वासरमैन

8
एक पुरातन सादृश्य का उपयोग करने के लिए, "फोन बुक" :-) नामक ये विशालकाय चीजें हुआ करती थीं और अगर मैंने आपसे किसी का नंबर देखने के लिए कहा और आपने कहा "उस व्यक्ति के लिए कोई संख्या नहीं है" तो मैं कहूंगा "आप क्या करते हैं" मतलब, वे एक असूचीबद्ध संख्या के साथ वहाँ हैं या आप बस उनके लिए एक प्रविष्टि नहीं पा सके हैं? " उन दो संभावित प्रतिक्रियाओं क्रमशः Optional.absent () और अशक्त करने के लिए मानचित्र। Optional.absent () निश्चित है "सकारात्मक नकारात्मक।"
केविन बोर्रिलिन

3
@ ब्रे: एक तरह से, Optional<T> यह "पाया गया, लेकिन मान्य नहीं" मान है। या अधिक सटीक रूप से, किसी भी प्रकार को "अतिरिक्त, लेकिन मान्य नहीं" के साथ सजानेOptional<T> का एक तरीका है - दो मौजूदा प्रकारों को मिलाकर एक नया प्रकार बनाना। यदि आपके पास सौ कक्षाएं हैं, तो हर एक के लिए एक अलग "पाया गया, लेकिन मान्य नहीं" मूल्य बनाना गड़बड़ हो सकता है, लेकिन आसानी से उन सभी के लिए काम कर सकता है। TOptional<T>
डैनियल प्राइडेन

9

यह वास्तव में Maybeहास्केल से मोनाड पैटर्न जैसा दिखता है ।

आपको निम्नलिखित विकिपीडिया मोनाड (कार्यात्मक प्रोग्रामिंग) को पढ़ना चाहिए :

और Kerflyn के ब्लॉग पर अमरूद के साथ वैकल्पिक से मोनाद तक पढ़ें , जिसमें एक मोनाड के रूप में उपयोग किए जाने वाले अमरूद के वैकल्पिक के बारे में चर्चा की गई है:


संपादित करें: Java8 के साथ, एक अंतर्निहित वैकल्पिक है जिसमें मौद्रिक ऑपरेटर जैसे हैं flatMap। यह एक विवादास्पद विषय रहा है लेकिन आखिरकार इसे लागू कर दिया गया है।

Http://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.html देखें

public Optional<String> tryFindSimilar(String s)  //...

Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);
Optional<String> similar =       opt.flatMap(this::tryFindSimilar);

flatMapऑपरेटर आसानी से श्रृंखला कॉल कि सभी वापसी वैकल्पिक परिणाम के लिए monadic संचालन, और परमिट की अनुमति देने के लिए आवश्यक है।

इसके बारे में सोचें, यदि आप mapऑपरेटर का उपयोग 5 बार करते हैं तो आप एक के साथ समाप्त हो जाएंगे Optional<Optional<Optional<Optional<Optional<String>>>>>, जबकि उपयोग flatMapआपको देगाOptional<String>

Java8 के बाद से मैं अमरूद के वैकल्पिक का उपयोग नहीं करूंगा जो कम शक्तिशाली है।


6

इसका उपयोग करने का एक अच्छा कारण यह है कि यह आपके नल को बहुत सार्थक बनाता है। एक अशक्त लौटाने के बजाय, जिसका अर्थ हो सकता है कि कई चीजें (जैसे त्रुटि, या विफलता, या खाली, आदि) आप अपने नल के लिए एक 'नाम' रख सकते हैं। इस उदाहरण को देखें:

एक बुनियादी POJO को परिभाषित करने देता है:

class PersonDetails {

String person;
String comments;

public PersonDetails(String person, String comments) {
    this.person = person;
    this.comments = comments;
}

public String getPerson() {
    return person;
}


public String getComments() {
    return comments;
}

}

अब इस सरल POJO का उपयोग करने देता है:

public Optional<PersonDetails> getPersonDetailstWithOptional () {

  PersonDetails details = null; /*details of the person are empty but to the caller this is meaningless,
  lets make the return value more meaningful*/


    if (details == null) {
      //return an absent here, caller can check for absent to signify details are not present
        return Optional.absent();
    } else {
      //else return the details wrapped in a guava 'optional'
        return Optional.of(details);   
    }
}

अब अशक्त का उपयोग करने से बचें और वैकल्पिक के साथ हमारी जाँच करें ताकि इसका सार्थक हो

public void checkUsingOptional () {

    Optional<PersonDetails> details = getPersonDetailstWithOptional();

    /*below condition checks if persons details are present (notice we dont check if person details are null,
    we use something more meaningful. Guava optional forces this with the implementation)*/
    if (details.isPresent()) {

      PersonDetails details = details.get();

        // proceed with further processing
        logger.info(details);

    } else {
        // do nothing
        logger.info("object was null"); 
    }

    assertFalse(details.isPresent());
}

इस प्रकार अंत में, अशक्तों को सार्थक बनाने का एक तरीका है, और कम अस्पष्टता।


4

वैकल्पिक का सबसे महत्वपूर्ण लाभ यह है कि यह किसी फ़ंक्शन के कार्यान्वयनकर्ता और कॉलर के बीच अनुबंध के लिए अधिक विवरण जोड़ता है। इस कारण से पैरामीटर और रिटर्न प्रकार दोनों के लिए उपयोगी है।

यदि आप सम्मेलन को हमेशा Optionalसंभव अशक्त वस्तुओं के लिए बनाते हैं तो आप इस तरह के मामलों में अधिक स्पष्टीकरण जोड़ सकते हैं:

  1. Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)

    यहां अनुबंध स्पष्ट रूप से निर्दिष्ट करता है कि एक मौका है कि एक परिणाम वापस नहीं किया गया है, लेकिन यह भी दर्शाता है कि यह अनुपस्थित के साथ fromऔर साथ काम करेगा to

  2. Optional<Integer> maxPrime(Optional<Integer> from, Integer to)

    अनुबंध निर्दिष्ट करता है कि से वैकल्पिक है इसलिए अनुपस्थित मान का एक विशेष अर्थ हो सकता है जैसे 2 से शुरू। मैं उम्मीद कर सकता हूं कि toपैरामीटर के लिए एक अशक्त मान अपवाद को फेंक देगा।

तो Optional का उपयोग करने का अच्छा हिस्सा यह है कि अनुबंध दोनों वर्णनात्मक ( @NotNullएनोटेशन के साथ समान ) हो गया, लेकिन औपचारिक भी है क्योंकि आपको .get()सामना करने के लिए कोड लिखना होगा Optional


जब एक खाली सूची क्लीनर होगी तो वैकल्पिक <सूची> का उपयोग क्यों करें?
RAY

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

2
संदर्भ के आधार पर, एक सूची में 0 आइटम और अनुपस्थित सूची के बीच एक सार्थक अंतर हो सकता है।
प्लाज्मा 147
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.