2015-03-01 8 views
14

क्या यह सच है कि जावा 1.8 लौटने के बाद Optional ऑब्जेक्ट अपवाद फेंकने से अधिक बेहतर है?वैकल्पिक बनाम अपवाद फेंकना

public Optional<?> get(int i) { 
     // do somtething 
     Object result = ... 
     Optional.ofNullable(result); 
    } 
इसके बजाय इस बात का

:

public Object get(int i) { 
     if(i<0 || i>=size) { 
      throw new IndexOutOfBoundsException("Index: " + i + ". Size: " + size); 
     } 
     // do somtething 
     Object result = ... 
     return result; 
    } 

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

+2

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

उत्तर

33

आपके द्वारा प्रस्तुत उदाहरण वैकल्पिक का उचित उपयोग नहीं है। एक खाली वैकल्पिक एक ऐसे मान का प्रतिनिधित्व करता है जो किसी कारण के लिए अनुपस्थित है जिसे कॉलर द्वारा भविष्यवाणी नहीं की जा सकती है। यह एक विधि के कानूनी आविष्कार का परिणाम है।

आपके द्वारा "पुराना मुहावरे" के रूप में मौजूद कोड इनपुट की मान्यता करता है और इनपुट अमान्य होने पर एक अनचेक अपवाद फेंकता है। यदि आप वैकल्पिक पेश करते हैं तो भी यह व्यवहार अपरिवर्तित रहना चाहिए। केवल अंतर यह होगा कि Object get(i) का वापसी मूल्य संभवतः शून्य है जबकि Optional<?> get(i) का वापसी मूल्य कभी शून्य नहीं होता है क्योंकि वैकल्पिक मान का एक विशेष राज्य मूल्य की अनुपस्थिति का प्रतिनिधित्व करता है।

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

static Optional<Type> componentType(Type type) { 
    return Optional.of(type) 
       .filter(t -> t instanceof ParameterizedType) 
       .map(t -> (ParameterizedType) t) 
       .filter(t -> t.getActualTypeArguments().length == 1) 
       .filter(t -> Optional.of(t.getRawType()) 
             .filter(rt -> rt instanceof Class) 
             .map(rt -> (Class<?>) rt) 
             .filter(Stream.class::isAssignableFrom) 
             .isPresent()) 
       .map(t -> t.getActualTypeArguments()[0]); 

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

बस रुचि के लिए, आप equals पूरी तरह से वैकल्पिक के मामले में लागू कर सकते हैं:

@Override public boolean equals(Object obj) { 
    return Optional.ofNullable(obj) 
       .filter(that -> that instanceof Test) 
       .map(that -> (Test)that) 
       .filter(that -> Objects.equals(this.s1, that.s1)) 
       .filter(that -> Objects.equals(this.s2, that.s2)) 
       .isPresent(); 
} 

हालांकि मैं इस मुहावरे बहुत साफ है और पठनीय मिल जाए, यह वर्तमान में पर्याप्त अनुकूल नहीं है एक उत्पादन योग्य विकल्प के रूप में सिफारिश की जा करने के लिए । हालांकि जावा के भविष्य के संस्करण इस व्यवहार्य बना सकते हैं।

+2

हालांकि मैं आपके तर्क से सहमत हूं, मुझे आश्चर्य है कि जब तक आप यहां मौजूद कोड को तब तक नहीं लेते हैं जब तक कि आपके द्वारा प्रस्तुत कोड मेरे लिए पठनीय नहीं है क्योंकि गैर-कार्यात्मक-शैली कोड होता। वाकई, इस मामले में मुझे लगता है कि पठनीयता के मामले में पुराना स्कूल कोड बेहतर है। लेकिन फिर, मैंने अपने जीवन में कभी भी हास्केल नहीं किया। –

+3

मैंने कभी भी हास्केल या किसी भी समान भाषा की एक पंक्ति नहीं लिखी है, लेकिन ईमानदारी से उनका उपयोग करने के कुछ हफ्तों के भीतर वैकल्पिक मुहावरे मेरे लिए प्राकृतिक बन गए हैं। बेशक, यह व्यक्तिगत है, लेकिन मेरी भविष्यवाणी यह ​​है कि अधिकांश लोगों को इसका उपयोग करने के लिए एक या दो महीने से अधिक की आवश्यकता नहीं होती है और लाभ उठाने लगते हैं। –

+0

मुझे 'वैकल्पिक 'से बचने के लिए' वैकल्पिक 'बहुत पसंद है, लेकिन' बहुत कम 'स्ट्रीम पर' मानचित्र 'और यहां तक ​​कि अधिक' फ़िल्टर' का उपयोग थोड़ा अजीब लगता है। –

21

अपवादों, नल और वैकल्पिक विकल्पों का दुरुपयोग करना संभव है। इस विशेष मामले में, मुझे लगता है कि आप शायद वैकल्पिक रूप से दुरुपयोग कर रहे हैं, क्योंकि आप चुपचाप एक पूर्व शर्त उल्लंघन छुपा रहे हैं और इसे सामान्य रिटर्न में परिवर्तित कर रहे हैं। आपके कोड से खाली विकल्प प्राप्त होने पर, कॉलर के पास "जो चीज मैं ढूंढ रहा था वह अलग नहीं थी" और "मैंने एक अमान्य प्रश्न पूछा" को अलग करने का कोई तरीका नहीं है।

क्योंकि वैकल्पिक नया है, इसके लिए अधिक उपयोग होने की प्रवृत्ति भी है; उम्मीद है कि समय के साथ सही पैटर्न आंतरिक हो जाएगा।

वैकल्पिक शून्य ऑब्जेक्ट पैटर्न का उदाहरण है; यह कहने का एक सुरक्षित तरीका प्रदान करता है कि "कुछ भी नहीं था" जब "कुछ भी नहीं" एक उचित अपेक्षित परिणाम है। (एक खाली सरणी या रिक्त संग्रह लौटाना उन डोमेन में समान उदाहरण हैं।) चाहे आप शून्य/वैकल्पिक बनाम "कुछ भी नहीं" का प्रतिनिधित्व करना चाहते हैं, एक अपवाद आमतौर पर एक कार्य है कि "कुछ भी नहीं" आमतौर पर अपेक्षित स्थिति है, या चाहे वह असाधारण है।उदाहरण के लिए, मैपिंग मौजूद नहीं होने पर कोई भी अपवाद फेंकने के लिए Map.get चाहता है; मैपिंग-न-उपस्थिति एक अपेक्षाकृत, असाधारण नहीं, परिणाम है। (अगर हम 1997 में Optional था, Map.get एक Optional लौटे सकता है।)

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

+2

एक स्पर्शरेखा पर, क्या वैकल्पिक रूप से वैकल्पिक आक्रामक अनुकूलन के आसपास कोई काम किया जा रहा है? जैसे कि जंजीर 'फिल्टर' आमंत्रण को कम सर्किट करना? मुझे अनौपचारिक आविष्कार वैकल्पिक के साथ लागू 'बराबर' के प्रदर्शन के अवक्रमण में महत्वपूर्ण कारक माना गया। –

+2

@MarkoTopolnik इस समय नहीं; हम बड़े लक्ष्य में हमारे अनुकूलन प्रयासों का निवेश कर रहे हैं। –

+0

_ रिक्त सरणी या रिक्त संग्रह को पुन: प्रस्तुत करना उन डोमेन में समान उदाहरण हैं ._ - तो क्यों JDK8 में वैकल्पिक वैकल्पिक-से-संग्रह पुल नहीं है जैसे Guava Optional.asSet? अजीब [वर्कअराउंड] है (http://stackoverflow.com/a/25239032/653539) - हालांकि आईएमएचओ अभी भी इसे जावा में जोड़ने में बहुत देर हो चुकी है। –

3

ऐसी स्थितियों में जहां त्रुटियां उत्पन्न हो सकती हैं, एक उपयुक्त डेटाटाइप कोशिश की जाती है।

abstractions 'वर्तमान' या 'खाली' का उपयोग करने के बजाय, एक प्रयास abstractions 'विफलता' या 'सफलता' का उपयोग करने का प्रयास करें।

जैसा कि बॉक्स 8 के बाहर जावा 8 द्वारा प्रदान नहीं किया गया है, कुछ 3. पार्टी लाइब्रेरी का उपयोग करना आवश्यक है। (हो सकता है कि हम इसे जावा 9 में जोड़ा देख सकेंगे?)

Try for Java

+0

या 'या तो'/'बाएं '/' दाएं' –

संबंधित मुद्दे