जावा 8 में एकाधिक अशक्त जाँच


99

मेरे पास नीचे का कोड है जो कई अशक्त जांचों के लिए थोड़ा बदसूरत है।

String s = null;

if (str1 != null) {
    s = str1;
} else if (str2 != null) {
    s = str2;
} else if (str3 != null) {
    s = str3;
} else {
    s = str4;
}

इसलिए मैंने Optional.ofNullableनीचे की तरह उपयोग करने की कोशिश की , लेकिन यह समझना मुश्किल है कि क्या कोई मेरा कोड पढ़ता है। जावा 8 में ऐसा करने के लिए सबसे अच्छा तरीका क्या है।

String s = Optional.ofNullable(str1)
                   .orElse(Optional.ofNullable(str2)
                                   .orElse(Optional.ofNullable(str3)
                                                   .orElse(str4)));

जावा 9 में, हम Optional.ofNullableसाथ उपयोग कर सकते हैं OR, लेकिन जावा 8 में कोई अन्य दृष्टिकोण है?


4
Java9 orसिंटैक्स String s = Optional.ofNullable(str1) .or(() -> Optional.ofNullable(str2)) .or(() -> Optional.ofNullable(str3)) .orElse(str4);उतना अच्छा नहीं लगता जितना कि Stream.ofमैं sya।
नमन

2
@ OleV.V। कुछ भी गलत नहीं है, ओपी पहले से ही इसके बारे में जानता है और जावा -8 के लिए कुछ विशिष्ट मांग रहा है।
नमन

3
मुझे पता है कि उपयोगकर्ता जावा -8 विशिष्ट समाधान के लिए पूछ रहा है, लेकिन एक सामान्य नोट पर, मैं साथ जाऊंगाStringUtils.firstNonBlank()
मोहम्मद अनीस

3
समस्या यह है कि, जावा 8 / स्ट्रीम इसके लिए सबसे अच्छा समाधान नहीं है। यह कोड वास्तव में एक रिफ्लेक्टर की तरह बदबू आ रही है, लेकिन अधिक संदर्भ के बिना यह बताना वास्तव में कठिन है। शुरुआत के लिए - तीन ऑब्जेक्ट्स क्यों नहीं हैं जो संभवतः एक संग्रह में पहले से ही इतने निकट से संबंधित हैं?
बिल के

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

जवाबों:


172

आप ऐसा कर सकते हैं:

String s = Stream.of(str1, str2, str3)
    .filter(Objects::nonNull)
    .findFirst()
    .orElse(str4);

16
यह। सोचें कि आपको क्या चाहिए, आपके पास नहीं है।
थोरबजोरन रावन एंडरसन

21
ओवरहेड कितना है? स्ट्रीम ऑब्जेक्ट बनाना, 4 तरीकों को कॉल करना, अस्थायी सरणियों का निर्माण ( {str1, str2, str3}) एक स्थानीय ifया की तुलना में बहुत धीमा लगता है ?:, जिसे जावा रनटाइम अनुकूलन कर सकता है। क्या javacजावा स्ट्रीमटाइम में कुछ स्ट्रीम-विशिष्ट अनुकूलन है जो इसे जितनी तेज़ी से बनाता है ?:? यदि नहीं, तो मैं इस समाधान को प्रदर्शन-महत्वपूर्ण कोड में अनुशंसित नहीं करूंगा।
अंक

16
@ इसे ?:कोड की तुलना में धीमा होने की संभावना है और मुझे यकीन है कि आपको प्रदर्शन-महत्वपूर्ण कोड में इससे बचना चाहिए। हालांकि यह बहुत अधिक पठनीय है और आपको इसे गैर-प्रदर्शन-महत्वपूर्ण-महत्वपूर्ण कोड IMO में अनुशंसित करना चाहिए, जो मुझे यकीन है कि 99% से अधिक कोड बनाता है।
हारून

7
@ चूँकि कोई स्ट्रीम विशिष्ट अनुकूलन नहीं हैं, न javacही रनटाइम में। यह सामान्य अनुकूलन को रोकता नहीं है, जैसे कोड के सभी को सम्मिलित करना, इसके बाद निरर्थक संचालन को समाप्त करना। सिद्धांत रूप में, अंतिम परिणाम सादे सशर्त अभिव्यक्तियों के रूप में कुशल हो सकता है, हालांकि, इसकी संभावना नहीं है कि यह कभी भी वहां पहुंचता है, क्योंकि रनटाइम केवल गर्म कोड पथों पर आवश्यक प्रयास खर्च करेगा।
होल्गर

22
महान समाधान! पठनीयता को थोड़ा बढ़ाने के लिए मैं अंत में और str4के मापदंडों को जोड़ने का सुझाव दूंगा। Stream.of(...)orElse(null)
danielp

73

टर्नरी सशर्त ऑपरेटर के बारे में कैसे?

String s = 
    str1 != null ? str1 : 
    str2 != null ? str2 : 
    str3 != null ? str3 : str4
;

50
वास्तव में, वह "Java8 में ऐसा करने के लिए सबसे अच्छा तरीका" ढूंढ रहा है। इस दृष्टिकोण का उपयोग जावा 8 में किया जा सकता है, इसलिए यह सब सिर्फ इस बात पर निर्भर करता है कि ओपी का अर्थ "सबसे अच्छा" क्या है, और वह किस आधार पर निर्णय लेता है कि क्या बेहतर है।
स्टूलटस्के

17
मैं आमतौर पर नेस्टेड टर्नरीज़ को नापसंद करता हूं, लेकिन यह बहुत साफ दिखता है।
जॉली जोकर

11
यह उन लोगों के लिए पार्स करने का एक बहुत बड़ा दर्द है जो हर दिन नेस्टेड टर्नरी ऑपरेटरों को नहीं पढ़ रहे हैं।
घन

2
@ क्यूबिक: यदि आपको लगता है कि पार्स करना कठिन है, तो एक टिप्पणी लिखें // take first non-null of str1..3। एक बार जब आप जानते हैं कि यह क्या करता है, तो यह देखना आसान हो जाता है कि कैसे।
पीटर कॉर्डेस

4
@ क्यूबिक फिर भी, यह एक सरल दोहराया पैटर्न है। एक बार जब आप पंक्ति 2 को पार कर लेते हैं, तो आपने पूरी बात को छोड़ दिया है, चाहे कितने भी मामले शामिल हों। और एक बार जब आप कर लेते हैं, तो आपने दस अलग-अलग मामलों के एक समान चयन को एक संक्षिप्त और अपेक्षाकृत सरल तरीके से व्यक्त करना सीख लिया है। अगली बार जब आप ?:सीढ़ी देखेंगे , तो आपको पता चलेगा कि यह क्या करता है। (Btw, कार्यात्मक प्रोग्रामर (cond ...)इसे क्लॉज़ के रूप में जानते हैं: यह हमेशा गार्ड के सत्य होने पर उपयोग करने के लिए उचित मूल्य के बाद एक गार्ड होता है।)
cmaster - reicaate monica

35

आप एक लूप का उपयोग भी कर सकते हैं:

String[] strings = {str1, str2, str3, str4};
for(String str : strings) {
    s = str;
    if(s != null) break;
}

27

वर्तमान उत्तर अच्छे हैं, लेकिन आपको वास्तव में इसे एक उपयोगिता विधि में रखना चाहिए:

public static Optional<String> firstNonNull(String... strings) {
    return Arrays.stream(strings)
            .filter(Objects::nonNull)
            .findFirst();
}

यह विधि मेरी Utilकक्षा में वर्षों से है, कोड को बहुत अधिक स्वच्छ बनाता है:

String s = firstNonNull(str1, str2, str3).orElse(str4);

आप इसे सामान्य भी बना सकते हैं:

@SafeVarargs
public static <T> Optional<T> firstNonNull(T... objects) {
    return Arrays.stream(objects)
            .filter(Objects::nonNull)
            .findFirst();
}

// Use
Student student = firstNonNull(student1, student2, student3).orElseGet(Student::new);

10
FWIW, SQL में, इस फ़ंक्शन को कोलेसस कहा जाता है , इसलिए मैं इसे अपने कोड में भी कहता हूं। क्या आपके लिए यह कार्य निर्भर करता है कि आप SQL को कितना पसंद करते हैं, वास्तव में।
टॉम एंडरसन

5
यदि आप इसे एक उपयोगिता विधि में रखने जा रहे हैं, तो आप इसे कुशल बना सकते हैं।
टॉड सेवेल

1
@ToddSewell, क्या मतलब है आपका?
गुस्तावो सिल्वा

5
@GustavoSilva टोड का मतलब शायद यह है कि, यह मेरी एक उपयोगिता पद्धति है, इसका उपयोग करने का कोई मतलब नहीं है Arrays.stream()जब मैं ए forऔर ए के साथ ऐसा कर सकता हूं != null, जो अधिक कुशल है। और टॉड सही होगा। हालाँकि, जब मैंने इस विधि को कोडित किया था, तो मैं ओपी की तरह, जावा 8 सुविधाओं का उपयोग करके ऐसा करने का एक तरीका ढूंढ रहा था, इसलिए ऐसा है।
Walen

4
@GustavoSilva हाँ मूल रूप से यह है कि: यदि आप इसे लगाने जा रहे हैं, तो यह एक साफ-सुथरे कोड के बारे में एक उपयोगी कार्य चिंता है जो अब महत्वपूर्ण नहीं है, और इसलिए आप एक तेज़ संस्करण का उपयोग कर सकते हैं।
टोड सेवेल

13

मैं एक सहायक फ़ंक्शन का उपयोग करता हूं, कुछ ऐसा

T firstNonNull<T>(T v0, T... vs) {
  if(v0 != null)
    return v0;
  for(T x : vs) {
    if (x != null) 
      return x;
  }
  return null;
}

फिर इस तरह का कोड लिखा जा सकता है

String s = firstNonNull(str1, str2, str3, str4);

1
अतिरिक्त v0पैरामीटर क्यों ?
टोबियास_

1
@tobias_k वेरिएग का उपयोग करते समय अतिरिक्त पैरामीटर 0 या अधिक के बजाय 1 या अधिक तर्कों की आवश्यकता के लिए जावा में मुहावरेदार तरीका है। (प्रभावी जावा, एड। 3. का आइटम 53 देखें, जो minएक उदाहरण के रूप में उपयोग करता है ।) मैं कम आश्वस्त हूं कि यह यहां उपयुक्त है।
निक

3
@ हाँ, मैंने जितना अनुमान लगाया था, लेकिन यह फ़ंक्शन ठीक उसी तरह काम करेगा (वास्तव में इसके बिना बिल्कुल वैसा ही व्यवहार करता है)।
तोबियास_

1
एक अतिरिक्त पहला तर्क पारित करने के लिए महत्वपूर्ण कारणों में से एक सरणी के पारित होने पर व्यवहार के बारे में स्पष्ट होना है। इस मामले में, मैं firstNonNull(arr)गिरफ्तार करना चाहता हूं यदि यह शून्य नहीं है। अगर ऐसा firstNonNull(T... vs)होता तो इसके बजाय गिरफ्तारी में पहली गैर-अशक्त प्रविष्टि वापस आ जाती।
माइकल एंडरसन

4

एक समाधान जो आप चाहते हैं के रूप में कई तत्व के लिए लागू किया जा सकता है:

Stream.of(str1, str2, str3, str4)
      .filter(Object::nonNull)
      .findFirst()
      .orElseThrow(IllegalArgumentException::new)

आप नीचे दिए गए समाधान की कल्पना कर सकते हैं, लेकिन पहले non nullityसभी तत्वों के लिए सुनिश्चित करता है

Stream.of(str1, str2, str3).....orElse(str4)

6
orElse str4वास्तव में एक अशक्त होने की प्रेरणा देता है
Naman

1
@nullpointer या orElseNull, जो str4शून्य है तो उसी के बराबर है।
तोबियास_

3

आप स्ट्रिंग की एक सरणी में सभी स्ट्रिंग्स को एक साथ जोड़ सकते हैं, फिर एक बार इसे असाइन करने के लिए लूप से चेक और ब्रेक करने के लिए लूप करें। एस 1, एस 2, एस 3, एस 4 को मानते हुए सभी स्ट्रिंग्स हैं।

String[] arrayOfStrings = {s1, s2, s3};


s = s4;

for (String value : arrayOfStrings) {
    if (value != null) { 
        s = value;
        break;
    }
}

डिफ़ॉल्ट रूप से s4 के लिए शर्त में फेंकने के लिए संपादित अगर कोई भी सौंपा नहीं है।


आपने छोड़ दिया है s4(या str4), जिसे sअंत में सौंपा जाना है, भले ही यह अशक्त हो।
DISPLAYNAME

3

विधि आधारित और सरल।

String getNonNull(String def, String ...strings) {
    for(int i=0; i<strings.length; i++)
        if(strings[i] != null)
             return s[i];
    return def;
}

और इसे इस प्रकार उपयोग करें:

String s = getNonNull(str4, str1, str2, str3);

यह सरणियों के साथ करना आसान है और सुंदर दिखता है।


0

यदि आप Apache Commons Lang 3 का उपयोग करते हैं तो इसे इस तरह लिखा जा सकता है:

String s = ObjectUtils.firstNonNull(str1, str2, str3, str4);

इसका उपयोग ObjectUtils.firstNonNull(T...)इस उत्तर से लिया गया था । संबंधित प्रश्न में विभिन्न दृष्टिकोण भी प्रस्तुत किए गए थे ।

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