2016-03-10 3 views
8

में जंजीर तुलना के लिए varargs और जेनेरिक संयोजन संयोजन यहां क्रैक करने के लिए एक कठिन अखरोट है। मैं एक साथ varargs और जेनेरिक का उपयोग करने के बीच एक संघर्ष है। दिए गए कोड के बाद:जावा

public class MyObject implements Comparable<MyObject> 
{ 
    private String name; 
    private int index; 

    @Override 
    public int compareTo(MyObject o) 
    { 
     if (name.compareTo(o.name) != 0) 
      return name.compareTo(o.name); 
     return ((Integer) index).compareTo(o.index); 
    } 
} 

मैं compareTo विधि से अधिक एक शर्त तुलना उपयोग करना चाहते हैं। यदि तार समान हैं तो इसके बजाय इंट्स का उपयोग करें। सामान्य स्थिति मैं कहूंगा।
मुझे सामान्य रूप से इसे संभालने के लिए एक स्थिर विधि बनाना अच्छा लगेगा। और मैं नई विधि chainedCompare इस तरह कहा जा करना चाहते हैं:

public int compareTo(MyObject o) 
{ 
    return chainedCompare(this, o, myO -> myO.name, myO -> myO.index); 
} 

lambdas जावा 8 इंटरफ़ेस समारोह की varargs हैं। तो सबसे पहले मुझे लगता है कि जैसे विधि ने लिखा है:

public static <T, C extends Comparable<C>> int chainedCompare(T object1, T object2, Function<T, C>... comparisons) 
{ 
    int compareValue = 0; 
    for (Function<T, C> comparison : comparisons) 
    { 
     compareValue = comparison.apply(object1).compareTo(comparison.apply(object2)); 
     if (compareValue != 0) 
      break; 
    } 
    return compareValue; 
} 

लेकिन मैं विचार नहीं किया कि इस मामले में सामान्य प्रकार सी varargs सरणी में सभी Function<T, C> तुलना के लिए एक ही प्रकार का होना चाहिए। जैसा कि आप ऊपर देख सकते हैं, मैं अलग-अलग तुलनाओं का उपयोग करना चाहता हूं (जैसे उदाहरण में स्ट्रिंग और इंटीजर)।
तो मैं यह इस संस्करण के लिए संशोधित:

public static <T> int chainedCompare(T object1, T object2, Function<T, ? extends Comparable<?>>... comparisons) 
{ 
    int compareValue = 0; 
    for (Function<T, ? extends Comparable<?>> comparison : comparisons) 
    { 
     compareValue = comparison.apply(object1).compareTo(comparison.apply(object2)); 
     if (compareValue != 0) 
      break; 
    } 
    return compareValue; 
} 

प्रकार सी यहाँ वाइल्डकार्ड साथ बदल दिया है। जबकि विधि कॉल अब काम करेगा, विधि compareTo के वाइल्डकार्ड टाइप पैरामीटर की वजह से संकलित नहीं होती है।

तो एक तरफ मुझे फ़ंक्शन इंटरफ़ेस के लिए एक निश्चित जेनेरिक प्रकार (तुलनात्मक रूप से विस्तारित) की आवश्यकता है, लेकिन दूसरी तरफ मुझे अलग-अलग (दूसरे) जेनेरिक प्रकारों के फ़ंक्शन इंटरफेस की आवश्यकता होती है जहां आप आमतौर पर वाइल्डकार्ड सेट कर सकते हैं। इसे कैसे हल करें?
मेरी एकमात्र आवश्यकता यह है कि मैं स्थैतिक विधि को सरल शर्तों के रूप में दिखा सकता हूं जैसा कि तुलना की शर्तों की एक अनिर्धारित संख्या के साथ दिखाया गया है।


Tunaki के सुझावों पर मैं इस प्रकार जो वांछित की तरह इस्तेमाल किया जा सकता विधि को संशोधित करने में सक्षम था आधार पर:

@SuppressWarnings("raw-types") 
public static <T> int chainedCompare(T object1, T object2, Function<T, ? extends Comparable>... comparisons) 
{ 
    return Arrays.stream(comparisons) 
     .map(Comparator::comparing) 
     .reduce(Comparator::thenComparing) 
     .map(c -> c.compare(object1, object2)) 
     .orElse(0); 
} 

public int compareTo(MyObject o) 
{ 
    return chainedCompare(this, o, myO -> myO.name, myO -> myO.index); 
} 

उत्तर

4

बजाय एक Comparable का उपयोग करने का, जिससे आप किसी Comparator उपयोग करने के लिए किया जाएगा :

public static <T> int chainedCompare(T object1, T object2, Comparator<T>... comparators) { 
    int compareValue = 0; 
    for (Comparator<? super T> comparator : comparators) { 
     compareValue = comparator.compare(object1, object2); 
     if (compareValue != 0) 
      break; 
    } 
    return compareValue; 
} 

तुम भी श्रृंखला सकता है सभी तुलनित्र एक साथ thenComparing का उपयोग करने और

है
@SafeVarargs 
public static <T> int chainedCompare(T object1, T object2, Comparator<T>... comparators) { 
    return Arrays.stream(comparators) 
       .reduce(Comparator::thenComparing) 
       .map(c -> c.compare(object1, object2)) 
       .orElse(0); 
} 

तो फिर तुम comparing(keyExtractor) साथ Comparator वस्तुओं या आदिम विशेषज्ञता comparingInt का निर्माण करके उपयोग कर सकते हैं कि।

@Override 
public int compareTo(MyObject o) { 
    return chainedCompare(this, o, 
      Comparator.comparing(obj -> obj.name), 
      Comparator.comparingInt(obj -> obj.index) 
      ); 
} 

इस दृष्टिकोण के साथ

, तो आप भी इस तरह के उपयोगिता के अस्तित्व पर सवाल खड़ा कर सकते हैं और बस

@Override 
public int compareTo(MyObject o) { 
    return Comparator.<MyObject, String> comparing(obj -> obj.name) 
        .thenComparingInt(obj -> obj.index) 
        .compare(this, o); 
} 
+0

एक अच्छा तरीका है कि है। यह भी अच्छा होगा, अगर मुझे अलग-अलग स्थिति के लिए Comparator.comparing() लिखना पड़ेगा। चूंकि तुलना() एक समारोह भी लेता है, इसलिए फंक्शन वर्रग्स को रखने और जंजीर कॉम्पैयर विधि के भीतर तुलनात्मक बनाने के लिए यह अच्छा होगा। लेकिन मुझे लगता है कि मेरे पास पहले की तरह ही सामान्य समस्या होगी, है ना? क्या यह असफल है? – Arceus

+0

@ एरसस हां, आप एक ही समस्या के तहत आते हैं। ध्यान दें कि मैंने एक और सरल समाधान के साथ एक संपादन किया है। – Tunaki

+0

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