जावा में पहला गैर-शून्य मान कैसे प्राप्त करें?


153

क्या SQL के COALESCEफ़ंक्शन के बराबर जावा है? यही है, क्या कई चर के पहले गैर-शून्य मूल्य को वापस करने का कोई तरीका है?

जैसे

Double a = null;
Double b = 4.4;
Double c = null;

मैं किसी भी तरह एक बयान है कि के पहले गैर-शून्य मान वापस आ जाएगी करना चाहते हैं a, bऔर c- इस मामले में, यह वापसी होगी b, या 4.4। (एसक्यूएल विधि की तरह कुछ - वापसी COALESCE(a,b,c))। मुझे पता है कि मैं इसे स्पष्ट रूप से कुछ इस तरह से कर सकता हूं:

return a != null ? a : (b != null ? b : c)

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


3
आपको इस तरह के फ़ंक्शन की आवश्यकता नहीं होनी चाहिए क्योंकि यदि आप चाहते हैं कि उत्तर 'b' है तो आप 'c' की गणना नहीं करेंगे। यानी आप केवल एक रखने के लिए संभावित उत्तरों की एक सूची नहीं बनाएंगे।
पीटर लॉरी

कैविएट: COALESCE पर सभी RDBMS शॉर्ट सर्किट नहीं। ओरेकल ने हाल ही में इसे करना शुरू किया।
एडम जेंट

3
@ BrainSlugs83 गंभीरता से? जावा चाहिए?
दिमित्री गिंजबर्ग

जवाबों:


108

नहीं, वहाँ नहीं है।

निकटतम आप प्राप्त कर सकते हैं:

public static <T> T coalesce(T ...items) {
    for(T i : items) if(i != null) return i;
    return null;
}

कुशल कारणों से, आप सामान्य मामलों को निम्न प्रकार से संभाल सकते हैं:

public static <T> T coalesce(T a, T b) {
    return a == null ? b : a;
}
public static <T> T coalesce(T a, T b, T c) {
    return a != null ? a : (b != null ? b : c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
    return ...
}

3
दक्षता के कारण जो मैंने ऊपर उल्लेख किया है वह यह है कि हर बार जब आप विधि के var arg संस्करण का आह्वान करते हैं तो एक सरणी आवंटन होगा। यह वस्तुओं के हाथ से भरे होने के लिए बेकार हो सकता है, जो मुझे संदेह है कि आम उपयोग होगा।
लेस 2

ठंडा। धन्यवाद। इस मामले में मैं शायद इस मामले में नेस्टेड सशर्त संचालकों से चिपके रहूंगा क्योंकि इसका उपयोग करने का एकमात्र समय है और उपयोगकर्ता द्वारा परिभाषित पद्धति ओवरकिल होगी ...
फ्रैडी

8
मैं अभी भी कोड में "डरावना दिखने वाला" सशर्त ब्लॉक छोड़ने के बजाय एक निजी सहायक विधि में इसे बाहर निकालूंगा - "वह क्या करता है?" इस तरह, यदि आपको कभी भी इसे फिर से उपयोग करने की आवश्यकता होती है, तो आप विधि को उपयोगिता वर्ग में स्थानांतरित करने के लिए अपने IDE में रीफैक्टरिंग टूल का उपयोग कर सकते हैं। नामित विधि होने से कोड के इरादे को दस्तावेज करने में मदद मिलती है, जो हमेशा एक अच्छी बात है, आईएमओ। (और नॉन वैर-आर्ग्स वर्जन का ओवरहेड शायद ही औसत दर्जे का है।)
les2

10
बाहर देखो: में coalesce(a, b), अगर bएक जटिल अभिव्यक्ति है और aनहीं है null, bअभी भी मूल्यांकन किया जाता है। यह सशर्त ऑपरेटर के लिए मामला नहीं है। इस जवाब को देखें ।
पंग

कॉल करने से पहले प्रत्येक तर्क को पूर्वगामी होने की आवश्यकता होती है, प्रदर्शन के कारणों के लिए व्यर्थ
इवान जी।


59

यदि जाँच करने के लिए केवल दो चर हैं और आप अमरूद का उपयोग कर रहे हैं, तो आप MoreObjects.firstNonNull (T प्रथम, T सेकंड) का उपयोग कर सकते हैं ।


49
ObjectffirstNonNull केवल दो तर्क लेता है; अमरूद में कोई भी वैरैग नहीं है। इसके अलावा, यह एक NullPointerException फेंकता है अगर दोनों args शून्य हैं - यह वांछनीय हो सकता है या नहीं।

2
अच्छी टिप्पणी, जेक। यह NullPointerException अक्सर Objects.firstNonNull के उपयोग को प्रतिबंधित करता है। हालाँकि, यह अमरुद के दृष्टिकोण से अशक्त लोगों से बचने के लिए है।
एंटोन शचस्टनी

4
यह विधि अब पदावनत है, और अनुशंसित विकल्प MoreObjects.firstNonNull है
davidwebster48

1
यदि एनपीई अवांछित है, तो इस उत्तर को
ऑरेंजडॉग

51

यदि परीक्षण करने के लिए केवल दो संदर्भ हैं और आप जावा 8 का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं

Object o = null;
Object p = "p";
Object r = Optional.ofNullable( o ).orElse( p );
System.out.println( r );   // p

यदि आप स्थैतिक वैकल्पिक आयात करते हैं तो अभिव्यक्ति बहुत खराब नहीं है।

दुर्भाग्यवश "कई चर" वाला आपका मामला वैकल्पिक-विधि से संभव नहीं है। इसके बजाय आप उपयोग कर सकते हैं:

Object o = null;
Object p = null;
Object q = "p";

Optional<Object> r = Stream.of( o, p, q ).filter( Objects::nonNull ).findFirst();
System.out.println( r.orElse(null) );   // p

23

LES2 के उत्तर के बाद, आप ओवरलोड फ़ंक्शन को कॉल करके कुशल संस्करण में कुछ पुनरावृत्ति को समाप्त कर सकते हैं:

public static <T> T coalesce(T a, T b) {
    return a != null ? a : b;
}
public static <T> T coalesce(T a, T b, T c) {
    return a != null ? a : coalesce(b,c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
    return a != null ? a : coalesce(b,c,d);
}
public static <T> T coalesce(T a, T b, T c, T d, T e) {
    return a != null ? a : coalesce(b,c,d,e);
}

5
सुंदर के लिए +1। साधारण लूप से अधिक दक्षता लाभों के बारे में निश्चित नहीं है, लेकिन अगर आप इस तरह से किसी भी छोटी दक्षता को निकालने जा रहे हैं, तो यह बहुत सुंदर हो सकता है।
कार्ल मैनस्टर 19

3
इस तरह से यह बहुत कम दर्दनाक और कम त्रुटि के कारण ओवरलोडेड वेरिएंट लिखने के लिए प्रवण बनाता है!
लेस

2
कुशल संस्करण का उपयोग किसी सरणी का उपयोग करके मेमोरी आवंटित नहीं करना था varargs। यहां, आप प्रत्येक नेस्टेड coalesce()कॉल के लिए स्टैक फ्रेम बनाकर मेमोरी को बर्बाद कर रहे हैं । कॉलिंग coalesce(a, b, c, d, e)गणना करने के लिए 3 स्टैक फ़्रेम तक बनाता है।
ल्यूक

10

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

कुछ इस तरह से कार्य करते हैं

public static <T> T coalesce(T ...items) 

उपयोग किया जाना चाहिए, लेकिन बाइट कोड में संकलित करने से पहले एक पूर्वप्रक्रमक होना चाहिए जो इस and कोलेसस फ़ंक्शन का उपयोग करता है ”और इसे निर्माण की जगह बदलता है

a != null ? a : (b != null ? b : c)

अद्यतन 2014-09-02:

जावा 8 और लैम्ब्डा के लिए धन्यवाद, जावा में सही तालमेल होने की संभावना है! महत्वपूर्ण विशेषता को शामिल करना: विशेष भावों का मूल्यांकन केवल जरूरत पड़ने पर किया जाता है - यदि पहले कोई अशक्त नहीं है, तो निम्नलिखित का मूल्यांकन नहीं किया जाता है (विधियों को नहीं बुलाया जाता है, गणना या डिस्क / नेटवर्क संचालन नहीं किया जाता है)।

मैंने इसके बारे में एक लेख लिखा जावा 8: coalesce - hledáme neNULLové hodnoty - (चेक में लिखा गया है, लेकिन मुझे आशा है कि कोड उदाहरण सभी के लिए समझ में आते हैं)।


1
अच्छा लेख - हालांकि, यह अंग्रेजी के लिए अच्छा होगा।
क्वांटम

1
उस ब्लॉग पेज के बारे में कुछ ऐसा है जो Google अनुवाद के साथ काम नहीं करता है। :-(
HairOfTheDog

5

अमरूद के साथ आप कर सकते हैं:

Optional.fromNullable(a).or(b);

जो एनपीई को फेंकता नहीं है यदि दोनों हैं aऔर bहैं null

संपादित करें: मैं गलत था, यह एनपीई फेंक देता है। मिशल wayizmazia द्वारा टिप्पणी के रूप में सही तरीका है:

Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();

1
अरे, यह करता है:java.lang.NullPointerException: use Optional.orNull() instead of Optional.or(null)
Michal mizmazia

1
यह चाल है:Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull()
मिकाल mizmazia

4

पूर्णता के लिए, "कई चर" मामला वास्तव में संभव है, हालांकि यह बिल्कुल भी सुरुचिपूर्ण नहीं है। उदाहरण के लिए, चर के लिए o, pऔर q:

Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )

कृपया ध्यान दें के उपयोग के orElseGet()मामले में भाग लेने कि o, p, औरq चर लेकिन भाव या तो महंगा या अवांछित दुष्प्रभाव के साथ नहीं हैं।

सबसे सामान्य मामले में coalesce(e[1],e[2],e[3],...,e[N])

coalesce-expression(i) ==  e[i]  when i = N
coalesce-expression(i) ==  Optional.ofNullable( e[i] ).orElseGet(()-> coalesce-expression(i+1) )  when i < N

यह अत्यधिक लंबे समय तक भाव उत्पन्न कर सकता है। हालांकि, अगर हम बिना किसी दुनिया में जाने की कोशिश कर रहे हैं null, तो v[i]शायद सबसे पहले से ही टाइप हैं Optional<String>, जैसा कि बस के विपरीत है String। इस मामले में,

result= o.orElse(p.orElse(q.get())) ;

या अभिव्यक्ति के मामले में:

result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;

इसके अलावा, यदि आप भी एक कार्यात्मक-कथात्मक शैली के लिए आगे बढ़ रहे हैं, o, p, और qप्रकार की होनी चाहिए Supplier<String>की तरह:

Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;

और फिर पूरी तरह से coalesceकम कर देता है o.get()

अधिक ठोस उदाहरण के लिए:

Supplier<Integer> hardcodedDefaultAge= ()-> 99 ;
Supplier<Integer> defaultAge= ()-> defaultAgeFromDatabase().orElseGet( hardcodedDefaultAge ) ;
Supplier<Integer> ageInStore= ()-> ageFromDatabase(memberId).orElseGet( defaultAge ) ;
Supplier<Integer> effectiveAge= ()-> ageFromInput().orElseGet( ageInStore ) ;

defaultAgeFromDatabase(), ageFromDatabase()और, ageFromInput()पहले से ही Optional<Integer>स्वाभाविक रूप से वापस आ जाएगा ।

और फिर coalesceबन जाता है effectiveAge.get()या बस effectiveAgeअगर हम एक के साथ खुश हैं Supplier<Integer>

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

मुझे एक ऐसा वर्ग याद आता है Lazy<T>जो Supplier<T>केवल एक बार ही आह्वान करता है , लेकिन आलसी, साथ ही Optional<T>(यानी Optional<T>- Optional<T>ऑपरेटरों, या यहां तक ​​कि Supplier<Optional<T>>) की परिभाषा में स्थिरता ।


4

आप यह कोशिश कर सकते हैं:

public static <T> T coalesce(T... t) {
    return Stream.of(t).filter(Objects::nonNull).findFirst().orElse(null);
}

इस प्रतिक्रिया के आधार पर


3

जब आप कुछ महंगी पद्धति का मूल्यांकन करने से बचना चाहते हैं तो आपूर्तिकर्ताओं का उपयोग कैसे करें?

ऐशे ही:

public static <T> T coalesce(Supplier<T>... items) {
for (Supplier<T> item : items) {
    T value = item.get();
    if (value != null) {
        return value;
    }
    return null;
}

और फिर इसे इस तरह से उपयोग करना:

Double amount = coalesce(order::firstAmount, order::secondAmount, order::thirdAmount)

आप दो, तीन या चार तर्कों के साथ कॉल के लिए अतिभारित तरीकों का भी उपयोग कर सकते हैं।

इसके अलावा, आप कुछ इस तरह से धाराओं का उपयोग भी कर सकते हैं:

public static <T> T coalesce2(Supplier<T>... s) {
    return Arrays.stream(s).map(Supplier::get).filter(Objects::nonNull).findFirst().orElse(null);
}

Supplierअगर यह वैसे भी निरीक्षण किया जाएगा तो पहले तर्क को क्यों लपेटें ? एकरूपता के लिए?
inego

0

कैसा रहेगा:

firstNonNull = FluentIterable.from(
    Lists.newArrayList( a, b, c, ... ) )
        .firstMatch( Predicates.notNull() )
            .or( someKnownNonNullDefault );

Java ArrayList आसानी से अशक्त प्रविष्टियों की अनुमति देता है और यह अभिव्यक्ति वस्तुओं की संख्या की परवाह किए बिना सुसंगत है। (इस रूप में, सभी वस्तुओं को एक ही प्रकार का होना चाहिए।)


-3
Object coalesce(Object... objects)
{
    for(Object o : object)
        if(o != null)
            return o;
    return null;
}

2
भगवान मैं जेनरिक से नफरत है। मैंने देखा कि तुम्हारे बल्ले से क्या मतलब था। मुझे @ LES2 को देखने के लिए दो बार देखना पड़ा कि वह एक ही काम कर रहा था (और शायद "बेहतर")! स्पष्टता के लिए +1
बिल K 18

हाँ, जेनरिक जाने का रास्ता है। लेकिन मैं उन सभी से परिचित नहीं हूं जो पेचीदगियों से परिचित हैं।
एरिक

10
जेनेरिक सीखने का समय :-)। @ LES2 के उदाहरण और इस, वस्तु के बजाय T के अलावा अन्य के बीच थोड़ा अंतर है। -1 एक फ़ंक्शन के निर्माण के लिए जो रिटर्न वैल्यू को डबल करने के लिए मजबूर करेगा। ऑल-कैप्स में जावा विधि के नामकरण के लिए भी, जो SQL में ठीक हो सकता है, लेकिन जावा में अच्छी शैली नहीं है।
एवीआई

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