अशक्त-सुरक्षित तुलना () कार्यान्वयन को सरल कैसे करें?


156

मैं compareTo()इस तरह के रूप में एक साधारण वर्ग के लिए विधि लागू कर रहा हूँ ( Collections.sort()जावा प्लेटफ़ॉर्म द्वारा उपयोग किए जाने वाले और अन्य उपहार देने में सक्षम होने के लिए ):

public class Metadata implements Comparable<Metadata> {
    private String name;
    private String value;

// Imagine basic constructor and accessors here
// Irrelevant parts omitted
}

मैं चाहता हूं कि इन वस्तुओं के लिए प्राकृतिक ऑर्डरिंग हो: 1) नाम द्वारा क्रमबद्ध और 2) मान द्वारा क्रमबद्ध अगर नाम समान है; दोनों तुलना मामले-असंवेदनशील होनी चाहिए। दोनों क्षेत्रों के लिए अशक्त मूल्य पूरी तरह से स्वीकार्य हैं, इसलिए compareToइन मामलों में नहीं टूटना चाहिए।

समाधान जो मन को स्प्रिंग्स करता है, वह निम्नलिखित की पंक्तियों के साथ है (मैं "गार्ड क्लॉस" का उपयोग कर रहा हूं जबकि अन्य एक एकल वापसी बिंदु पसंद कर सकते हैं, लेकिन यह बिंदु के बगल में है):

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(Metadata other) {
    if (this.name == null && other.name != null){
        return -1;
    }
    else if (this.name != null && other.name == null){
        return 1;
    }
    else if (this.name != null && other.name != null) {
        int result = this.name.compareToIgnoreCase(other.name);
        if (result != 0){
            return result;
        }
    }

    if (this.value == null) {
        return other.value == null ? 0 : -1;
    }
    if (other.value == null){
        return 1;
    }

    return this.value.compareToIgnoreCase(other.value);
}

यह काम करता है, लेकिन मैं इस कोड से पूरी तरह से खुश नहीं हूं। माना जाता है कि यह बहुत जटिल नहीं है, लेकिन काफी वाचाल और थकाऊ है।

सवाल यह है कि आप इस क्रिया को कम कैसे करेंगे (कार्यक्षमता को बनाए रखते हुए)? यदि वे मदद करते हैं तो जावा मानक पुस्तकालयों या अपाचे कॉमन्स को संदर्भित करने के लिए स्वतंत्र महसूस करें। क्या इसे (थोड़ा) सरल बनाने का एकमात्र विकल्प मेरे अपने "NullSafeStringComparator" को लागू करना और इसे दोनों क्षेत्रों की तुलना करने के लिए लागू करना होगा?

संपादन 1-3 : एडी का अधिकार; ऊपर "दोनों नाम शून्य हैं" मामला तय किया गया

स्वीकृत उत्तर के बारे में

मैंने यह सवाल 2009 में जावा 1.6 के पाठ्यक्रम पर वापस पूछा था, और उस समय एडी द्वारा शुद्ध JDK समाधान मेरे लिए स्वीकृत उत्तर था। मुझे अब (2017) तक बदलने के लिए कभी नहीं मिला।

वहाँ भी 3 पार्टी पुस्तकालय समाधान कर रहे हैं - 2009 Apache कॉमन्स संग्रह एक और एक 2013 अमरूद दोनों, मेरे द्वारा पोस्ट - कि मैं कुछ समय में पसंद किया था।

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


जवाबों:


173

जावा 8 का उपयोग करना :

private static Comparator<String> nullSafeStringComparator = Comparator
        .nullsFirst(String::compareToIgnoreCase); 

private static Comparator<Metadata> metadataComparator = Comparator
        .comparing(Metadata::getName, nullSafeStringComparator)
        .thenComparing(Metadata::getValue, nullSafeStringComparator);

public int compareTo(Metadata that) {
    return metadataComparator.compare(this, that);
}

7
मैं अपाचे कॉमन्स लैंग के पक्ष में जावा 8 बिल्ट-इन सामान का उपयोग करने का समर्थन करता हूं, लेकिन यह है कि जावा 8 कोड काफी बदसूरत है, और अभी भी पुष्टि करता है। मैं इस समय org.apache.commons.lang3.builder.CompareToBuilder के साथ रहूंगा।
jschreiner

1
यह Collections.sort (Arrays.asList (null, val1, null, val2, null)) के लिए काम नहीं करता है क्योंकि यह एक तुच्छ वस्तु पर ComparTo () को कॉल करने का प्रयास करेगा। यह संग्रह की रूपरेखा के साथ एक समस्या की तरह दिखता है ईमानदार होना, यह पता लगाने की कोशिश करना कि यह कैसे कोने में है।
पेड्रो बोर्ग्स

3
@PedroBorges लेखक ने कंटेनर की वस्तुओं को छांटने के बारे में पूछा था जो कि छांटे जाने योग्य फ़ील्ड (जहाँ उन फ़ील्ड्स अशक्त हो सकते हैं) के बारे में हैं, नॉट कंटेनर कंटेनरों को सॉर्ट करने के बारे में। इसलिए, जब आपकी टिप्पणी सही है, तो वह Collections.sort(List)काम नहीं करता है जब सूची में अशक्तियाँ हैं, टिप्पणी प्रश्न के लिए प्रासंगिक नहीं है।
स्क्रब करें

211

आप बस Apache Commons Lang का उपयोग कर सकते हैं :

result = ObjectUtils.compare(firstComparable, secondComparable)

4
(@Kong: यह अशक्त-सुरक्षा का ध्यान रखता है लेकिन मामले की असंवेदनशीलता का नहीं जो मूल प्रश्न का दूसरा पहलू था। इस प्रकार स्वीकृत उत्तर को नहीं बदला जा सकता है।)
जोनिक

3
इसके अलावा, मेरे दिमाग में अपाचे कॉमन्स को 2013 में स्वीकृत जवाब नहीं होना चाहिए। (भले ही कुछ उपप्रोजेक्ट दूसरों की तुलना में बनाए रखे गए हों।) अमरूद का उपयोग उसी चीज को प्राप्त करने के लिए किया जा सकता है ; देखें nullsFirst()/ nullsLast()
जोनीक

8
@ जोनिक आपको क्यों लगता है कि अपाचे कॉमन्स को 2013 में स्वीकृत जवाब नहीं होना चाहिए?
वास्तव

1
अपाचे कॉमन्स के बड़े हिस्से विरासत / खराब बनाए रखने वाले / कम गुणवत्ता वाले सामान हैं। ज्यादातर चीजों के लिए बेहतर विकल्प हैं जो इसे प्रदान करते हैं, उदाहरण के लिए अमरूद में जो कि एक बहुत ही उच्च गुणवत्ता वाला काम है, और खुद जेडीके में तेजी से बढ़ रहा है। 2005 के आसपास हाँ, अपाचे कॉमन्स गंदगी थी, लेकिन इन दिनों अधिकांश परियोजनाओं में इसकी कोई आवश्यकता नहीं है। (निश्चित रूप से, अपवाद हैं; उदाहरण के लिए अगर मुझे किसी कारण से एफ़टीपी क्लाइंट की आवश्यकता होती है, तो मैं शायद अपाचे कॉमन्स नेट में एक का उपयोग करूंगा, और इसी तरह।)
जोनीक जुएल

6
@ जेनिक, आप अमरूद का उपयोग करके इस प्रश्न का उत्तर कैसे देंगे? आपका दावा है कि अपाचे कॉमन्स लैंग (पैकेज org.apache.commons.lang3) "विरासत / खराब तरीके से बनाए रखा गया / कम-गुणवत्ता वाला" गलत या कम निराधार है। कॉमन्स लैंग 3 को समझना और उपयोग करना आसान है, और यह सक्रिय रूप से बनाए रखा गया है। यह शायद मेरी सबसे अधिक उपयोग की जाने वाली लाइब्रेरी है (स्प्रिंग फ्रेमवर्क और स्प्रिंग सिक्योरिटी के अलावा) - इसके अशक्त-सुरक्षित तरीकों के साथ स्ट्रिंगरिल्ट्स वर्ग उदाहरण के लिए इनपुट सामान्यीकरण को तुच्छ बनाता है।
पॉल

93

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

ध्यान दें: आपका तुलनित्र ऊपर, यदि दोनों नाम शून्य हैं, तो मूल्य फ़ील्ड की तुलना भी नहीं करेंगे। मुझे नहीं लगता कि आप यही चाहते हैं।

मैं इसे कुछ इस तरह से लागू करूंगा:

// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(final Metadata other) {

    if (other == null) {
        throw new NullPointerException();
    }

    int result = nullSafeStringComparator(this.name, other.name);
    if (result != 0) {
        return result;
    }

    return nullSafeStringComparator(this.value, other.value);
}

public static int nullSafeStringComparator(final String one, final String two) {
    if (one == null ^ two == null) {
        return (one == null) ? -1 : 1;
    }

    if (one == null && two == null) {
        return 0;
    }

    return one.compareToIgnoreCase(two);
}

EDIT: कोड नमूने में फिक्स्ड टाइपोस। यही कारण है कि मुझे पहले इसका परीक्षण नहीं करने के लिए मिलता है!

संपादित करें: nullSafeStringComparator को स्थिर करने के लिए प्रचारित करें।


2
नेस्टेड "अगर" के बारे में ... मुझे लगता है कि इस मामले के लिए कम पठनीय होना चाहिए, इसलिए मैं इससे बचता हूं। हां, कभी-कभी इसके कारण एक अनावश्यक तुलना होगी। मापदंडों के लिए अंतिम आवश्यक नहीं है, लेकिन एक अच्छा विचार है।
एडी

31
XOR का मधुर उपयोग
जेम्स मैकमोहन

9
@phihag - मुझे पता है कि यह 3 साल से अधिक है, लेकिन ... finalकीवर्ड वास्तव में आवश्यक नहीं है (जावा कोड पहले से ही जैसा है वैसा ही है।) हालांकि, यह स्थानीय संस्करणों (एक भयानक कोडिंग अभ्यास) के रूप में मापदंडों के पुन: उपयोग को रोकता है। सॉफ्टवेयर के बारे में हमारी सामूहिक समझ समय के साथ बेहतर होती जाती है, हम जानते हैं कि डिफ़ॉल्ट रूप से चीजें अंतिम / कास्ट / इनअम्यूट होनी चाहिए। इसलिए मैं प्राप्त करने finalके लिए पैरामीटर घोषणाओं (हालांकि फ़ंक्शन को तुच्छ हो सकता है) का उपयोग करने में थोड़ी अतिरिक्त क्रियाशीलता पसंद करता हूं inmutability-by-quasi-default। चीजों की भव्य योजना में इसकी व्यापकता / रखरखाव की क्षमता नगण्य है।
luis.espinal

24
@ जेम्स मैकमोहन मुझे असहमत होना पड़ा। Xor (^) को बस नहीं-बराबर (! =) से बदला जा सकता है। यह समान बाइट कोड के लिए भी संकलित है। = = बनाम ^ का उपयोग केवल स्वाद और पठनीयता का मामला है। इसलिए, इस तथ्य को देखते हुए कि आप आश्चर्यचकित थे कि मैं कहूंगा कि यह यहां नहीं है। जब आप चेकसम की गणना करने का प्रयास कर रहे हों, तो एक्सोर का उपयोग करें। ज्यादातर अन्य मामलों में (जैसे यह) चलो! = से चिपके रहते हैं।
bvdb

5
स्ट्रिंग के स्थान पर T, T के रूप में घोषित करके इस उत्तर का विस्तार करना आसान है, <T को तुलनीय कहा जाता है <T >> ... और फिर हम सुरक्षित रूप से किसी भी अशोभनीय तुलनीय वस्तुओं की तुलना कर सकते हैं
Thierry

20

अमरूद का उपयोग करके अद्यतन (2013) समाधान के लिए इस उत्तर के नीचे देखें।


यह वही है जो मैं अंततः साथ चला गया। यह निकला कि हमारे पास पहले से ही अशक्त-सुरक्षित स्ट्रिंग तुलना के लिए एक उपयोगिता विधि थी, इसलिए इसका सबसे सरल समाधान था कि इसका उपयोग किया जाए। (यह एक बड़ा कोडबेस है; इस तरह की बात को याद रखना आसान है :)

public int compareTo(Metadata other) {
    int result = StringUtils.compare(this.getName(), other.getName(), true);
    if (result != 0) {
        return result;
    }
    return StringUtils.compare(this.getValue(), other.getValue(), true);
}

यह है कि हेल्पर को कैसे परिभाषित किया जाता है (यह अतिभारित है ताकि आप यह भी परिभाषित कर सकें कि नल पहले या आखिरी में आते हैं, यदि आप चाहते हैं कि:

public static int compare(String s1, String s2, boolean ignoreCase) { ... }

तो यह अनिवार्य रूप से एडी के जवाब के समान है (हालांकि मैं एक स्थिर सहायक विधि को एक तुलनित्र नहीं कहूंगा ) और उज़ की भी।

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

संपादित करें (2009): अपाचे कॉमन्स कलेक्शन संस्करण

दरअसल, यहां अपाचे कॉमन्स पर आधारित समाधान को NullComparatorसरल बनाने का एक तरीका है। कक्षा में प्रदान किए गए केस-असंवेदनशील केComparator साथ इसे मिलाएं String:

public static final Comparator<String> NULL_SAFE_COMPARATOR 
    = new NullComparator(String.CASE_INSENSITIVE_ORDER);

@Override
public int compareTo(Metadata other) {
    int result = NULL_SAFE_COMPARATOR.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return NULL_SAFE_COMPARATOR.compare(this.value, other.value);
}

अब यह बहुत सुंदर है, मुझे लगता है। (बस एक छोटी सी समस्या बनी हुई है: कॉमन्स NullComparatorजेनेरिक का समर्थन नहीं करता है, इसलिए एक अनियंत्रित असाइनमेंट है।)

अद्यतन (2013): अमरूद संस्करण

लगभग 5 साल बाद, यहाँ बताया गया है कि मैं अपने मूल प्रश्न से कैसे निपटूँगा। यदि जावा में कोडिंग है, तो मैं (निश्चित रूप से) अमरूद का उपयोग करूंगा । (और निश्चित रूप से अपाचे कॉमन्स नहीं ।)

इसे कहीं और रखें, जैसे "स्ट्रिंगरिल्स" क्लास में:

public static final Ordering<String> CASE_INSENSITIVE_NULL_SAFE_ORDER =
    Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast(); // or nullsFirst()

फिर, इसमें public class Metadata implements Comparable<Metadata>:

@Override
public int compareTo(Metadata other) {
    int result = CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.name, other.name);
    if (result != 0) {
        return result;
    }
    return CASE_INSENSITIVE_NULL_SAFE_ORDER.compare(this.value, other.value);
}    

बेशक, यह अपाचे कॉमन्स संस्करण के लगभग समान है (दोनों ही JDK के CASE_INSENSITIVE_ORDER का उपयोग करते हैं), nullsLast()केवल अमरूद-विशिष्ट चीज होने का उपयोग । यह संस्करण केवल इसलिए बेहतर है क्योंकि अमरूद कॉमन्स कलेक्शन के लिए एक निर्भरता के रूप में बेहतर है। (जैसा कि सभी सहमत हैं ।)

यदि आप इस बारे में सोच रहे थे Ordering, तो ध्यान दें कि यह लागू होता है Comparator। यह विशेष रूप से अधिक जटिल छंटनी की जरूरतों के लिए बहुत आसान है, उदाहरण के लिए आपको कई आदेशों का उपयोग करने की अनुमति देता है compound()। अधिक के लिए समझाया आदेश पढ़ें !


2
String.CASE_INSENSITIVE_ORDER वास्तव में समाधान को बहुत साफ करता है। अच्छा अद्यतन।
पैट्रिक

2
यदि आप वैसे भी अपाचे कॉमन्स का उपयोग करते हैं, तो ए ComparatorChain तो आपको अपनी स्वयं की compareToविधि की आवश्यकता नहीं है ।
अमीबी

13

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

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

आपके मामले में आपके पास एक स्थिर सदस्य चर हो सकता है जो तुलना करता है और फिर आपकी compareToविधि केवल संदर्भ देती है।

जैसी भावना

class Metadata implements Comparable<Metadata> {
private String name;
private String value;

static NullComparator nullAndCaseInsensitveComparator = new NullComparator(
        new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                // inputs can't be null
                return o1.compareToIgnoreCase(o2);
            }

        });

@Override
public int compareTo(Metadata other) {
    if (other == null) {
        return 1;
    }
    int res = nullAndCaseInsensitveComparator.compare(name, other.name);
    if (res != 0)
        return res;

    return nullAndCaseInsensitveComparator.compare(value, other.value);
}

}

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


धन्यवाद, मैं उम्मीद कर रहा था कि कॉमन्स में ऐसा कुछ होगा! इस मामले में, हालाँकि, मैंने इसका उपयोग नहीं किया: stackoverflow.com/questions/481813/…
जोनीक

बस एहसास हुआ कि String.CASE_INSENSITIVE_ORDER का उपयोग करके आपके दृष्टिकोण को सरल बनाया जा सकता है; मेरे संपादित अनुवर्ती उत्तर देखें।
जोनिक

यह अच्छा है लेकिन "अगर (अन्य == अशक्त) {" चेक नहीं होना चाहिए। तुलना करने के लिए Javadoc का कहना है कि अगर किसी अन्य शून्य है, तो ComparT को NullPointerException को फेंक देना चाहिए।
डैनियल अलेक्सियस

7

मुझे पता है कि यह सीधे आपके सवाल का जवाब नहीं हो सकता है, क्योंकि आपने कहा था कि अशक्त मूल्यों का समर्थन करना होगा।

लेकिन मैं सिर्फ यह नोट करना चाहता हूं कि तुलना में नल का समर्थन करना तुलना के लिए आधिकारिक जावास्क्रिप्ट में वर्णित तुलना अनुबंध के अनुरूप नहीं है :

ध्यान दें कि null किसी भी वर्ग का उदाहरण नहीं है, और e.compareTo (null) को NullPointerException को फेंकना चाहिए, भले ही e.equals (शून्य) गलत हो।

इसलिए मैं या तो NullPointerException को स्पष्ट रूप से फेंक दूंगा या बस इसे पहली बार फेंका जाएगा जब अशक्त तर्क को स्थगित किया जा रहा है।


4

आप विधि निकाल सकते हैं:

public int cmp(String txt, String otherTxt)
{
    if ( txt == null )
        return otjerTxt == null ? 0 : 1;

    if ( otherTxt == null )
          return 1;

    return txt.compareToIgnoreCase(otherTxt);
}

public int compareTo(Metadata other) {
   int result = cmp( name, other.name); 
   if ( result != 0 )  return result;
   return cmp( value, other.value); 

}


2
क्या "0: 1" नहीं "0: -1" होना चाहिए?
रॉल्फ क्रिस्टेन्सन

3

आप अपनी कक्षा को अपरिवर्तनीय होने के लिए डिज़ाइन कर सकते हैं (प्रभावी जावा 2 एड। इस पर एक बड़ा भाग है, आइटम 15: उत्परिवर्तन को कम करें) और निर्माण पर सुनिश्चित करें कि कोई नल संभव नहीं है (और यदि आवश्यक हो तो अशक्त ऑब्जेक्ट पैटर्न का उपयोग करें )। फिर आप उन सभी चेक को छोड़ सकते हैं और मान सकते हैं कि मान शून्य नहीं हैं।


हां, यह आम तौर पर एक अच्छा समाधान है, और कई चीजों को सरल करता है - लेकिन यहां मुझे उस मामले में अधिक दिलचस्पी थी जहां शून्य मानों को एक कारण या किसी अन्य के लिए अनुमति दी जाती है, और इसे ध्यान में रखा जाना चाहिए :)
जोनिक

2

मैं कुछ इसी तरह की तलाश में था और यह थोड़ा जटिल लग रहा था इसलिए मैंने ऐसा किया। मुझे लगता है कि इसे समझना थोड़ा आसान है। आप इसे एक तुलनित्र के रूप में या एक लाइनर के रूप में उपयोग कर सकते हैं। इस प्रश्न के लिए आप तुलना को बदल देंगे। के रूप में, नल ऊपर तैर रहे हैं। यदि आप उन्हें डूबाना चाहते हैं तो आप 1, -1 को फ्लिप कर सकते हैं।

StringUtil.NULL_SAFE_COMPARATOR.compare(getName(), o.getName());

public class StringUtil {
    public static final Comparator<String> NULL_SAFE_COMPARATOR = new Comparator<String>() {

        @Override
        public int compare(final String s1, final String s2) {
            if (s1 == s2) {
                //Nulls or exact equality
                return 0;
            } else if (s1 == null) {
                //s1 null and s2 not null, so s1 less
                return -1;
            } else if (s2 == null) {
                //s2 null and s1 not null, so s1 greater
                return 1;
            } else {
                return s1.compareTo(s2);
            }
        }
    }; 

    public static void main(String args[]) {
        final ArrayList<String> list = new ArrayList<String>(Arrays.asList(new String[]{"qad", "bad", "sad", null, "had"}));
        Collections.sort(list, NULL_SAFE_COMPARATOR);

        System.out.println(list);
    }
}

2

हम java 8 का उपयोग ऑब्जेक्ट के बीच अशक्त-अनुकूल तुलना करने के लिए कर सकते हैं। माना जाता है कि मैं 2 क्षेत्रों के साथ एक लड़का वर्ग है: स्ट्रिंग नाम और पूर्णांक उम्र और मैं पहले नाम और फिर उम्र की तुलना करना चाहता हूं अगर दोनों समान हैं।

static void test2() {
    List<Boy> list = new ArrayList<>();
    list.add(new Boy("Peter", null));
    list.add(new Boy("Tom", 24));
    list.add(new Boy("Peter", 20));
    list.add(new Boy("Peter", 23));
    list.add(new Boy("Peter", 18));
    list.add(new Boy(null, 19));
    list.add(new Boy(null, 12));
    list.add(new Boy(null, 24));
    list.add(new Boy("Peter", null));
    list.add(new Boy(null, 21));
    list.add(new Boy("John", 30));

    List<Boy> list2 = list.stream()
            .sorted(comparing(Boy::getName, 
                        nullsLast(naturalOrder()))
                   .thenComparing(Boy::getAge, 
                        nullsLast(naturalOrder())))
            .collect(toList());
    list2.stream().forEach(System.out::println);

}

private static class Boy {
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Boy(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "name: " + name + " age: " + age;
    }
}

और परिणाम:

    name: John age: 30
    name: Peter age: 18
    name: Peter age: 20
    name: Peter age: 23
    name: Peter age: null
    name: Peter age: null
    name: Tom age: 24
    name: null age: 12
    name: null age: 19
    name: null age: 21
    name: null age: 24

1

यदि कोई भी स्प्रिंग का उपयोग करता है, तो एक वर्ग है। org.springframework.util.comparator.NullSafeComparator जो आपके लिए भी ऐसा करता है। बस अपने आप को इसके साथ इस तरह से सजाएं

new NullSafeComparator<YourObject>(new YourComparable(), true)

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/comparator/NullSafeComparator.html


1

उस विशिष्ट मामले के लिए जहां आप जानते हैं कि डेटा में नल नहीं होंगे (हमेशा तार के लिए एक अच्छा विचार) और डेटा वास्तव में बहुत बड़ा है, आप अभी भी मूल्यों की तुलना करने से पहले तीन तुलना कर रहे हैं, यदि आप जानते हैं कि यह आपका मामला है , आप एक बालक बिट का अनुकूलन कर सकते हैं। YMMV पठनीय कोड के रूप में मामूली अनुकूलन को रौंद देता है:

        if(o1.name != null && o2.name != null){
            return o1.name.compareToIgnoreCase(o2.name);
        }
        // at least one is null
        return (o1.name == o2.name) ? 0 : (o1.name != null ? 1 : -1);

1
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Comparator;

public class TestClass {

    public static void main(String[] args) {

        Student s1 = new Student("1","Nikhil");
        Student s2 = new Student("1","*");
        Student s3 = new Student("1",null);
        Student s11 = new Student("2","Nikhil");
        Student s12 = new Student("2","*");
        Student s13 = new Student("2",null);
        List<Student> list = new ArrayList<Student>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s11);
        list.add(s12);
        list.add(s13);

        list.sort(Comparator.comparing(Student::getName,Comparator.nullsLast(Comparator.naturalOrder())));

        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            Student student = (Student) iterator.next();
            System.out.println(student);
        }


    }

}

आउटपुट है

Student [name=*, id=1]
Student [name=*, id=2]
Student [name=Nikhil, id=1]
Student [name=Nikhil, id=2]
Student [name=null, id=1]
Student [name=null, id=2]

1

NullSafe तुलनित्र का उपयोग करने का एक सरल तरीका यह है कि वसंत कार्यान्वयन का उपयोग किया जाए, नीचे दिए गए सरल उदाहरणों में से एक है:

public int compare(Object o1, Object o2) {
        ValidationMessage m1 = (ValidationMessage) o1;
        ValidationMessage m2 = (ValidationMessage) o2;
        int c;
        if (m1.getTimestamp() == m2.getTimestamp()) {
            c = NullSafeComparator.NULLS_HIGH.compare(m1.getProperty(), m2.getProperty());
            if (c == 0) {
                c = m1.getSeverity().compareTo(m2.getSeverity());
                if (c == 0) {
                    c = m1.getMessage().compareTo(m2.getMessage());
                }
            }
        }
        else {
            c = (m1.getTimestamp() > m2.getTimestamp()) ? -1 : 1;
        }
        return c;
    }

0

एक और अपाचे ObjectUtils उदाहरण। अन्य प्रकार की वस्तुओं को छाँटने में सक्षम।

@Override
public int compare(Object o1, Object o2) {
    String s1 = ObjectUtils.toString(o1);
    String s2 = ObjectUtils.toString(o2);
    return s1.toLowerCase().compareTo(s2.toLowerCase());
}

0

यह मेरा कार्यान्वयन है जो मैं अपने ArrayList को सॉर्ट करने के लिए उपयोग करता हूं। अशक्त वर्गों को अंतिम रूप दिया जाता है।

मेरे मामले के लिए, EntityPhone EntityAbstract का विस्तार करता है और मेरा कंटेनर सूची <EntityAbstract> है।

"safeIfNull ()" विधि का उपयोग अशक्त सुरक्षित छँटाई के लिए किया जाता है। अन्य विधियां पूर्णता के लिए हैं, यह दिखाती है कि तुलनाफल का उपयोग कैसे किया जा सकता है।

@Nullable
private static Integer compareIfNull(EntityPhone ep1, EntityPhone ep2) {

    if (ep1 == null || ep2 == null) {
        if (ep1 == ep2) {
            return 0;
        }
        return ep1 == null ? -1 : 1;
    }
    return null;
}

private static final Comparator<EntityAbstract> AbsComparatorByName = = new Comparator<EntityAbstract>() {
    @Override
    public int compare(EntityAbstract ea1, EntityAbstract ea2) {

    //sort type Phone first.
    EntityPhone ep1 = getEntityPhone(ea1);
    EntityPhone ep2 = getEntityPhone(ea2);

    //null compare
    Integer x = compareIfNull(ep1, ep2);
    if (x != null) return x;

    String name1 = ep1.getName().toUpperCase();
    String name2 = ep2.getName().toUpperCase();

    return name1.compareTo(name2);
}
}


private static EntityPhone getEntityPhone(EntityAbstract ea) { 
    return (ea != null && ea.getClass() == EntityPhone.class) ?
            (EntityPhone) ea : null;
}

0

यदि आप एक साधारण हैक चाहते हैं:

arrlist.sort((o1, o2) -> {
    if (o1.getName() == null) o1.setName("");
    if (o2.getName() == null) o2.setName("");

    return o1.getName().compareTo(o2.getName());
})

यदि आप सूची के अंत में नल लगाना चाहते हैं तो बस इसे ऊपर के मेट्रो में बदलें

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