2016-06-27 5 views
9

मुझे लगता है कि optionals अब जावा मानक लाइब्रेरी में हैं। लेकिन एक मूल समस्या है जिसमें मैं चल रहा हूं जिसमें मुझे पता नहीं लगाया गया है कि कैसे सर्वोत्तम (आसानी से पढ़ने और समझने, सबसे सुंदर, सबसे छोटा) तरीका हल करने के लिए:वैकल्पिक विकल्प खाली होने पर वापस कैसे करें?

वैकल्पिक होने पर विधि से कैसे वापस आना है खाली है?

मैं एक सामान्य समाधान की तलाश में हूं जो वैकल्पिक विकल्पों और कोड ब्लॉक के आकार के विभिन्न संयोजनों के लिए काम करता है। वैकल्पिक और संक्षिप्तता के सुरक्षित रूप से प्रकार:

void m1() { 
    // When I get an optional: 
    Optional<String> o = getOptional(); 

    // And want to return if it's empty 
    if (!o.isPresent()) return; 

    // In the whole rest of the method I have to call Optional.get 
    // every time I want the value: 
    System.out.println(o.get()); 

    // Which is pretty ugly and verbose! 
} 


void m2() { 
    // If I instead return null if a value is absent: 
    String s = getNullabe(); 
    if (s == null) return; 

    // Then I can use the value directly: 
    System.out.println(s); 
} 

यह सवाल कैसे ऊपर दोनों उदाहरण के अच्छे पहलू पाने के लिए के बारे में है:

निम्न उदाहरण में मैं दिखाने के लिए मैं क्या मतलब है की कोशिश करेंगे निरर्थक प्रकार के।

बाकी के उदाहरण इस और अधिक दिखाते हैं।

void m3() { 
    // If I on the other hand want to throw on empty that's pretty and compact: 
    String s = getOptional() 
     .orElseThrow(IllegalStateException::new); 

    System.out.println(s); 
} 

void m4() { 
    Optional<String> o = getOptional(); 
    if (!o.isPresent()) return; 

    // I can of course declare a new variable for the un-optionalised string: 
    String s = o.get(); 

    System.out.println(s); 

    // But the old variable still remains in scope for the whole method 
    // which is ugly and annoying. 
    System.out.println(o.get()); 
} 


void m5() { 
    // This is compact and maybe pretty in some ways: 
    getOptional().ifPresent(s -> { 
     System.out.println(s); 

     // But the extra level of nesting is annoying and it feels 
     // wrong to write all the code in a big lambda. 

     getOtherOptional().ifPresent(i -> { 
      // Also, more optional values makes it really weird and 
      // pretty hard to read, while with nullables I would 
      // get no extra nesting, it would looks good and be 
      // easy to read. 
      System.out.println("i: " + i); 

      // It doesn't work in all cases either way. 
     }); 
    }); 
} 


Optional<String> getOptional() { 
    throw new UnsupportedOperationException(); 
} 

Optional<Integer> getOtherOptional() { 
    throw new UnsupportedOperationException(); 
} 

String getNullabe() { 
    throw new UnsupportedOperationException(); 
} 

कैसे मैं एक विधि से लौटा सकते हैं या एक वैकल्पिक खाली है विधि के बाकी हिस्सों में get का उपयोग किए बिना, एक अतिरिक्त चर घोषित करने के बिना और ब्लॉक घोंसले के अतिरिक्त स्तरों के बिना?

या यदि यह सब प्राप्त करना संभव नहीं है, तो इस स्थिति को संभालने का सबसे अच्छा तरीका क्या है?

+0

वास्तव में 'if (वैकल्पिक.isPresent()) {...} 'के साथ कुछ भी गलत नहीं है। 'वैकल्पिक '' शून्य' से अधिक अर्थपूर्ण मान जोड़ता है, इसलिए मिशन पूरा हुआ। पठनीयता और अल्पसंख्यक अक्सर एक अच्छा संतुलन होते हैं। "बदसूरत" और "verbose" यहां इस तरह के अतिव्यक्ति हैं। – Radiodef

+0

@Lii यदि आप अधिक सामान्य मामले (वैकल्पिक प्रकार के विकल्प और संचालन) में रूचि रखते हैं, तो कृपया इसे अपने प्रश्न में जोड़ें। यदि आपके पास समान प्रकार और समान ऑपरेशन हैं तो यह एक अलग उपयोग केस है। – user140547

+1

यह सभी उदाहरण जैसे उदाहरण वैकल्पिक विकल्प का उपयोग सबसे अच्छा समाधान नहीं है ... –

उत्तर

11

आप orElse(null) इस्तेमाल कर सकते हैं:

getOptional().ifPresent(System.out::println); 

यह:

String o = getOptional().orElse(null); 
if (o == null) { 
    return; 
} 
+2

मेरा पहला विचार था: "महोदय, तो मैं सिर्फ नलिकाओं का उपयोग करने के लिए वापस आ गया हूं।"लेकिन एक दूसरे विचार पर शायद यह इतना बुरा नहीं है! क्योंकि मूल्य की संभावित अनुपस्थिति अभी भी 'getOptional' के प्रकार में दिखाई दे रही है, और नलिका स्ट्रिंग का उपयोग एक छोटे से दायरे में किया जाता है जहां यह बहुत स्पष्ट है कि क्या हो रहा है। – Lii

+0

आह, अब मैंने इसे कुछ वास्तविक कोड में आजमाया है और मुझे इसे और अधिक पसंद है! मेरे कोड से पहले से ही आधा दर्जन पसीकी हो गया है। धन्यवाद! – Lii

+0

वास्तव में? और क्यों एक और स्तर नहीं जोड़ना: ' बूलियन नोडाटा = (ओ == नल); अगर (नोडाटा) {वापसी;} ' –

5

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

// And want to return if it's empty 
if (!o.isPresent()) return; 

के लिए एक विकल्प के रूप में क्यों नहीं बस शर्त है, जो नेस्टेड मामले में अच्छी तरह से काम करता है, भी रिवर्स? वापसी स्पष्ट बनाने के लिए कोई ज़रूरत नहीं है:

if (o.isPresent()) { 
    System.out.println(o.get()); 
    if (oo.isPresent()) { 
    System.out.println(oo.get()); 
    } 
} 

हालांकि, उपयोग के मामले में इस तरह का सुझाव है कि आप वास्तव में वैकल्पिक से लाभ नहीं कर रहे हैं के रूप में एक नल मूल्य के लिए विरोध किया। आम तौर पर, यदि आप isPresent का उपयोग कर रहे हैं और प्राप्त करते हैं, तो वैकल्पिक शायद आपको वह सब कुछ नहीं मिल रहा है (सिवाय इसके कि यह आपको उस मामले पर विचार करने के लिए मजबूर करता है जहां मूल्य गुम है)। IfPresent, मानचित्र, फ़िल्टर, और अन्य "अधिक कार्यात्मक" विधियों का उपयोग वैकल्पिक मान के लिए अधिक विशिष्ट उपयोग हो सकता है।


लेकिन किसी भी मामले में, जब आप वैकल्पिक विकल्प का वादा कर रहे हों तो कृपया वापस न आएं। यद्यपि ऑब्जेक्ट की अपेक्षा होने पर शून्य को वापस करने के लिए पूरी तरह से कानूनी है, वैकल्पिक विकल्प का बिंदु ठीक से जांचने से बचने के लिए है।तो क्या करते हो नहीं:

Optional<String> getOptional() { 
    return null; 
} 

लेकिन इसके बजाय कार्य करें:

Optional<String> getOptional() { 
    return Optional.empty(); 
} 

नहीं तो आप क्या करने वाले अंत:

Optional<String> o = getOptional(); 
if (o != null && o.isPresent()) { 
    // ... 
} 

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

+0

अक्सर लैम्ब्डा में निष्पादित करने के लिए कोड का ब्लॉक बहुत बड़ा होता है, इसलिए यह अधिकतर समय का विकल्प नहीं है। – Lii

+0

@Lii यदि यह कोड का एक बड़ा ब्लॉक है, तो यह काफी संभव है कि इसे अपनी विधि में निकाला जाना चाहिए, जिसे आसानी से विधि संदर्भ के रूप में पारित किया जा सकता है। –

+0

हे, आप सुझाव देते हैं कि जब मैं चाहता हूं कि मैं दोनों से बचने के लिए घोंसले और 'मिल' कॉल दोनों का उपयोग करता हूं! मुझे लगता है कि पूर्व शर्त के कुछ चेक के साथ एक विधि शुरू करने के लिए यह बहुत स्पष्ट है और फिर विफल होने पर वापस लौटें। यह पाठकों को तत्काल स्पष्ट करता है कि चेक विफल होने पर क्या होता है, और यह विधि के पूरे शेष भाग के लिए घोंसले के कई स्तरों को बचा सकता है। – Lii

0

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

void m4() { 
    Optional<String> o = getOptional(); 
    if (!o.isPresent()) return; 

    doThings(o.get()); 
} 

void doThings(String s){ 
    System.out.println(s); 
    //do whatever else with the string. 
} 

इस तरह आप केवल दायरे में स्ट्रिंग है और आप .get() हर आप इसे उपयोग करना चाहते हैं कॉल करने के लिए की जरूरत नहीं है: तो अपने कार्य कुछ इस तरह हो जाता है।

+1

एचएम। लेकिन फिर मुझे 'डॉटिंग' के साथ सभी तर्कों को 'm4' पर पास करना होगा। और अधिकांश समय मैं अपने समाधान को विधियों में विभाजित नहीं करना चाहता हूं, इस पर आधारित कि मैं वैकल्पिक के साथ काम कर रहा हूं। – Lii

+1

@ एलआई नहीं, आपको उन सभी को पारित करने की ज़रूरत नहीं है; आपको केवल उन लोगों को पास करना होगा जो ** ** करना ** * जरूरत * है। सवाल में आपकी चिंताओं में से एक यह था कि कुछ वस्तुओं के मुकाबले बहुत अधिक गुंजाइश थी। किसी अन्य विधि से दोबारा प्रतिक्रिया करके, और मूल्यों को पास करके, आप व्यापक क्षेत्रों से बच सकते हैं। –

+0

जब यह केवल एक मान (स्ट्रिंग) है, हालांकि; 'if (! o.isPresent()) वापसी;' अनावश्यक लगता है। पूरा 'एम 4' विधि निकाय बस हो सकता है: 'getOptional()। IfPresent (यह :: doThings); '। –

6

आप ifPresent

optional.ifPresent(System.out::println); 

किसी अन्य विधि वापसी कि विधि की तुलना में वैकल्पिक पर निर्भर करता है, तो उपयोग कर सकते हैं और map तरीकों के बजाय, अगर समारोह शून्य है और आप दुष्प्रभाव क्या करने की जरूरत आप ifPresent उपयोग कर सकते हैं, हो सकता है साथ ही एक वैकल्पिक लौट सकते हैं और नक्शा विधि

Optional<Integer> getLength(){ 
    Optional<String> hi = Optional.of("hi"); 
    return hi.map(String::length) 
} 

अधिकांश समय जब आप कॉल की उपयोग करने की आवश्यकता isPresent और 0,123,, आप Optional का दुरुपयोग कर रहे हैं।

+0

उदाहरण में विधि 'm5' देखें, यह दर्शाता है कि मैं ऐसा क्यों नहीं करना चाहता हूं। मुझे लगता है कि जब आप एक छोटी सी चीज करते हैं तो 'ifPresent' का उपयोग ठीक है। लेकिन यदि आप बहुत सी चीजें करते हैं और/या कई विकल्प हैं तो घोंसले का स्तर जल्दी से बदसूरत और पढ़ने में मुश्किल बनाता है। – Lii

+0

@Lii आप नए तरीकों से लंबे ब्लॉक को स्थानांतरित/विभाजित कर सकते हैं, है ना? –

+0

@ करलोस ह्यूबरर: हाँ, लेकिन अक्सर मैं यह तय नहीं करना चाहता कि मेरे प्रोग्राम को केवल तभी बनाया जाए जब मुझे वैकल्पिक मूल्य से निपटना पड़े। और अक्सर एक विधि पहले कुछ पूर्व शर्त का परीक्षण करती है और अगर वे नहीं पकड़ती हैं तो समाप्त हो जाती है। कभी-कभी उन पूर्व शर्तएं हैं कि एक वैकल्पिक मान खाली नहीं है। – Lii

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