2017-03-26 9 views
9

मैं निम्नलिखित संग्रह वर्ग है कि एक नक्शा जहां प्रत्येक मूल्य वर्ग के प्रकार है में तत्वों के समूहीकरण के लिए एक विधि शामिल यहजावा संग्रह और उपवर्गों

class TaskCollection<E extends Task> extends HashSet<E> { 
    <K> Map<K, ? extends TaskCollection<E>> groupBy(Function<E, K> groupingFunction) { 
     return this.stream() 
      .collect(Collectors.groupingBy(
        groupingFunction, 
        Collectors.toCollection(this.collectionConstructor()) 
      )); 
    } 

    Supplier<? extends TaskCollection<E>> collectionConstructor() { 
     return TaskCollection::new; 
    } 
} 

लागू किया है, तो मुझे क्या करना चाहते हैं groupBy विधि का उपयोग करने वाले उप-वर्ग बनाने में सक्षम होने के लिए जो मानचित्र मानों के रूप में स्वयं के नए नियमों को लौटाता है।
निम्नलिखित एक उदाहरण

class AssertionCollection extends TaskCollection<Assertion> { 
    Map<Person, AssertionCollection> groupByPerson() { 
     return this.groupBy(Assertion::assignedPerson); 
    } 

    @Override 
    Supplier<AssertionCollection> collectionConstructor() { 
     return AssertionCollection::new; 
    } 
} 

समस्या groupByPerson विधि में है। कंपाइलर groupBy कॉल के लिए एक त्रुटि फेंकता है।

Error:(15, 28) java: incompatible types: no instance(s) of type variable(s) K exist so that java.util.Map<K,? extends TaskCollection<Assertion>> conforms to java.util.Map<Person,AssertionCollection>

मैं जावा में नया तो मैं यकीन है कि वहाँ कुछ बेवकूफ मैं नहीं दिख रहा है कर रहा हूँ कर रहा हूँ

+2

आपके कार्यान्वयन के बारे में एक टिप्पणी: ऐसा लगता है कि 'टास्ककोलेक्शन' में 'टास्ककोलेक्शन' की तुलना में 'हैशसेट' बेहतर समझ में आता है, 'हैशसेट' है। 'हैशसेट' का उपयोग एक कार्यान्वयन विस्तार की तरह लगता है। क्या आपको 'हैशसेट' से उत्तराधिकारी होने की आवश्यकता है? – scottb

उत्तर

4

मंशा है कि किसी भी वर्ग X कि TaskCollection फैली हुई है, जब एक GroupBy ऑपरेशन है के लिए प्रदर्शन किया गया, नक्शा मूल्यों के लिए उपयोग किया गया संग्रह वर्ग X के उदाहरण भी हैं। उनके GroupBy नक्शा मूल्यों के लिए एक और TaskCollection वर्ग का उपयोग करने का

class Task {} 

class Assertion extends Task {} 

abstract class TaskCollection<E extends Task, C extends TaskCollection<E, C>> extends HashSet<E> { 

    <K> Map<K, C> groupBy(Function<E, K> groupingFunction) { 
     return this.stream() 
      .collect(Collectors.groupingBy(
        groupingFunction, 
        Collectors.toCollection(this.collectionSupplier()) 
      )); 
    } 

    protected abstract Supplier<C> collectionSupplier(); 
} 

class AssertionCollection extends TaskCollection<Assertion, AssertionCollection> { 

    @Override 
    protected Supplier<AssertionCollection> collectionSupplier() { 
     return AssertionCollection::new; 
    } 
} 

उपवर्गों सूचना है कि TaskCollection की परिभाषा से ऊपर काफी नहीं रुकती:

उस मामले में, निकटतम आपको लगता है कि करने के लिए प्राप्त कर सकते हैं निम्नलिखित की तरह कुछ है । उदाहरण के लिए यह भी संकलन होगा:

class AssertionCollectionOther extends TaskCollection<Assertion, AssertionCollectionOther> {...} 

class AssertionCollection extends TaskCollection<Assertion, AssertionCollectionOther> {...} 

दुर्भाग्य से यह कम से कम अब के लिए, इस तरह के एक बाधा लागू करने के लिए संभव नहीं है, जैसा कि आप वर्ग सी प्रकार पैरामीटर वाइल्डकार्ड में घोषित किया जा रहा है के संदर्भ में नहीं कर सकता।

यदि आप मान सकते हैं कि वंश के पास आपूर्तिकर्ता के रूप में पैरामीटर मुक्त कन्स्ट्रक्टर है तो आप collectionSupplier के लिए एक डिफ़ॉल्ट कार्यान्वयन प्रदान कर सकते हैं। आपके द्वारा भुगतान की जाने वाली कीमत को "अनचेक" चेतावनी (वास्तविक समस्या नहीं) को चुप करने की आवश्यकता है और यह अनुपालन वर्ग नहीं है (पैरामीटर मुक्त कन्स्ट्रक्टर प्रदान नहीं कर रहा है) संकलन समय पर असफल नहीं होगा लेकिन रन-टाइम पर जो कम आदर्श है :

import java.util.function.*; 
import java.util.*; 
import java.util.stream.*; 

class Task {} 

class Assertion extends Task {} 

class TaskCollection<E extends Task, C extends TaskCollection<E, C>> extends HashSet<E> { 

    <K> Map<K, C> groupBy(Function<E, K> groupingFunction) { 
     return this.stream() 
      .collect(Collectors.groupingBy(
        groupingFunction, 
        Collectors.toCollection(this.collectionSupplier()) 
      )); 
    } 

    @SuppressWarnings("unchecked") 
    protected Supplier<C> collectionSupplier() { 
     return() -> { 
     try { 
      return (C) this.getClass().newInstance(); 
     } catch (Exception ex) { 
      throw new RuntimeException(String.format("class %s is not a proper TaskCollection", this.getClass()), ex); 
     } 
     }; 
    } 
} 

class AssertionCollection extends TaskCollection<Assertion, AssertionCollection> { 
    // This override is not needed any longer although still could 
    // be included in order to produce a slightly faster 
    // customized implementation: 
    //@Override 
    //protected Supplier<AssertionCollection> collectionSupplier() { 
    // return AssertionCollection::new; 
    //} 
} 

आप यह घोषणा करते हैं collectionSupplierfinal के रूप में आप को प्रभावी ढंग से हमेशा चेतावनी के साथ अपने ही वर्ग के उदाहरण वापस जाने के लिए है कि एक है, तो गैर-भावना, घोषणा जैसे class AssertionCollection extends TaskCollection<Assertion, AssertionCollectionOther> अभी भी संकलन और रन-टाइम का उत्पादन करेगा उपवर्गों मजबूर होना पड़ा सड़क के नीचे अपवाद कास्ट।

+1

यही वह है जिसे मैं ढूंढ रहा था! धन्यवाद – Fed03

+1

मैंने अपना बदसूरत जवाब हटा दिया है। अच्छा जवाब, और वोट वोट। –

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