2015-11-04 8 views
25

मैं एक वर्गजावा 8 - चेनिंग निर्माता कॉल और stream.map में सेटर()

class Foo{ 
    String name; 
    // setter, getter 
} 

जो सिर्फ एक डिफ़ॉल्ट निर्माता है की है।

फिर, मैं कुछ स्ट्रिंग से Foo की एक सूची बनाने के लिए कोशिश कर रहा हूँ:

Arrays.stream(fooString.split(",")) 
      .map(name -> { 
       Foo x = new Foo(); 
       x.setName(name); 
       return x; 

      }).collect(Collectors.toList())); 

चूंकि कोई निर्माता है जो एक नाम लेता है, मैं बस एक विधि संदर्भ का उपयोग नहीं कर सकते हैं। बेशक, मैं उन तीन लाइनों को कन्स्ट्रक्टर कॉल और सेटर के साथ एक विधि में निकाल सकता हूं लेकिन क्या ऐसा करने के लिए कोई बेहतर या संक्षिप्त तरीका है?

+0

अगर केवल स्ट्रीम में ज़िप था ... – njzk2

उत्तर

24

इस बार-बार होता है, तो आप एक सामान्य उपयोगिता विधि एक वस्तु को देखते हुए एक संपत्ति के मूल्य के निर्माण की समस्या से निपटने बना सकते हैं:

public static <T,V> Function<V,T> create(
    Supplier<? extends T> constructor, BiConsumer<? super T, ? super V> setter) { 
    return v -> { 
     T t=constructor.get(); 
     setter.accept(t, v); 
     return t; 
    }; 
} 

तो फिर तुम इसे पसंद का उपयोग हो सकता है:

List<Foo> l = Arrays.stream(fooString.split(",")) 
    .map(create(Foo::new, Foo::setName)).collect(Collectors.toList()); 

नोट यह Foo के लिए विशिष्ट नहीं है और न ही इसकी setName विधि:

List<List<String>> l = Arrays.stream(fooString.split(",")) 
    .map(create(ArrayList<String>::new, List::add)).collect(Collectors.toList()); 

वैसे, अगर fooString बहुत बड़े हो जाता है और/या तत्वों (बंटवारे के बाद) के बहुत सारे हो सकती है, यह अधिक Pattern.compile(",").splitAsStream(fooString) बजाय Arrays.stream(fooString.split(",")) उपयोग करने के लिए कुशल हो सकता है।

8

इस मामले यदि आप बहुत अधिक विकल्प नहीं है जब तक आप एक निर्माता पैरामीटर के रूप में नाम लेने जोड़ने के लिए, या आप एक static factory method कि आपके उदाहरण बनाने बनाने में (Foo है, जो एक उत्पन्न फ़ाइल है बदले बिना)।

11

नहीं, कोई बेहतर तरीका नहीं है।

एकमात्र विकल्प है, जैसे आप अपने सवाल में कहा, Foo वस्तुओं के लिए एक कारखाना बनाने के लिए:

public class FooFactory { 
    public static Foo fromName(String name) { 
     Foo foo = new Foo(); 
     foo.setName(name); 
     return foo; 
    } 
} 

और इस तरह इसका इस्तेमाल:

Arrays.stream(fooString.split(",")).map(FooFactory::fromName).collect(toList()); 

अगर वहाँ के एक बहुत हैं विभाजित करने के लिए नाम, Arrays.stream(fooString.split(",")) के बजाय आप Pattern.compile(",").splitAsStream(fooString) (और मनोरंजन से बचने के लिए स्थिर में संकलित पैटर्न को स्टोर कर सकते हैं) का उपयोग कर सकते हैं।

3

एक और विकल्प जिसे अभी तक कोई भी उल्लेख नहीं किया गया है, Foo वर्ग को उपclass करना होगा, हालांकि इसमें कुछ नुकसान हो सकते हैं - यह कहना मुश्किल है कि यह आपकी समस्या का उचित समाधान होगा, क्योंकि मुझे संदर्भ पता नहीं है।

public class Bar extends Foo { 

    public Bar(String name) { 
     super.setName(name); 
    } 

} 
3

.map(n -> new Foo() {{ name = n; }})

यह एक उदाहरण-चर सेट करने के लिए एक प्रारंभ ब्लॉक का उपयोग करता है।

हालांकि एक चेतावनी है: लौटाई गई वस्तुएं वास्तव में Foo टाइप नहीं होंगी, लेकिन नई, अज्ञात कक्षाएं जो Foo का विस्तार करती हैं।जब आप लिस्कोव प्रतिस्थापन सिद्धांत का पालन करते हैं तो यह कोई समस्या नहीं होनी चाहिए, लेकिन ऐसी कुछ स्थितियां हैं जहां यह चिंता हो सकती है।

+0

... या: .map (n -> new foo() {{setName (n);}}) –

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