2015-10-21 4 views
8

के साथ फ़ंक्शन तर्कों की चर लंबाई को स्वीकार करे मान लीजिए मेरे पास एक स्ट्रिंग है: String s = "1,2,3,4,5,6"। मैं एक विधि combineFunctions() बनाना चाहता हूं जो एक तर्क के रूप में Function एस का परिवर्तनीय लंबाई अनुक्रम लेगा और उस क्रम में सभी परिचालनों को लागू करेगा।एक ऐसी विधि बनाएं जो संभवतः विभिन्न प्रकार

कार्यों में <T,U> प्रकार भिन्न हो सकते हैं।

उदाहरण इस तरह के एक समारोह के उपयोग करता होगा निम्नलिखित:

Combine<String> c = new Combine<>(s); 
List<String> numbers = c.combineFunctions(splitByComma); 
Integer max = c.combineFunctions(splitByComma,convertToInt, findMax); 

मैं क्या कोशिश की है (यहाँ <U> की ज्यादा का उपयोग नहीं है):

public <U> void combineFunctions(
     Function<? extends Object, ? extends Object>... functions) { 

} 

लेकिन मैं पर अटक कर रहा हूँ Function एस के अंतिम में से एक का प्रकार प्राप्त करना। मैं एक पुनरावर्ती दृष्टिकोण के बारे में भी सोच रहा था लेकिन varargs पैरामीटर अंतिम होना चाहिए।

जावा में ऐसी विधि को लागू करना संभव होगा?

+0

इसका मतलब क्या है "लेकिन मैं कार्यों में से किसी एक को प्राप्त करने में फंस गया हूं।" क्या आप समझा सकते हैं? –

+4

यह 'स्ट्रीम' और' मानचित्र 'विधि जैसा दिखता है। – gontard

+3

यदि आप जानते हैं कि इसे हमेशा अपेक्षाकृत कम संख्या में तर्क (10 कार्यों से कम कहें) के साथ बुलाया जाएगा, तो आप 10 ओवरलोडेड 'गठबंधन (फ़ंक्शन फ़ंक्शन , ..., फ़ंक्शन ) लिख सकते हैं। विभिन्न (लेकिन सीमित) तर्कों को स्वीकार करते समय यह प्रकार सुरक्षा को बनाए रखने का एक मानक तरीका है। – assylias

उत्तर

3

ऐसे फ़ंक्शन के साथ समस्या यह है कि आप सभी संकलन-समय प्रकार की जांच और कास्टिंग आवश्यक है।

यह एक साथ क्रियाओं को गठबंधन करने के लिए andThen का उपयोग करके एक कार्यान्वयन होगा। यह सभी कास्टिंग की वजह से बदसूरत लग रहा है और मुझे यकीन नहीं है कि आप इसे और अधिक सही तरीके से कर सकते हैं। ध्यान दें कि इसके लिए केवल 2 वास्तव में आवश्यक होने पर 2 स्ट्रीम पाइपलाइनों के निर्माण की आवश्यकता होती है।

public static void main(String[] args) throws Exception { 
    String str = "1,2,3,4,5,6"; 
    Function<Object, Object> splitByComma = s -> ((String) s).split(","); 
    Function<Object, Object> convertToInt = tokens -> Stream.of((String[]) tokens).map(Integer::valueOf).toArray(Integer[]::new); 
    Function<Object, Object> findMax = ints -> Stream.of((Integer[]) ints).max(Integer::compare).get(); 
    Integer max = (Integer) combineFunctions(splitByComma, convertToInt, findMax).apply(str); 
    System.out.println(max); 
} 

@SafeVarargs 
private static Function<Object, Object> combineFunctions(Function<Object, Object>... functions) { 
    return Arrays.stream(functions) 
       .reduce(Function::andThen) 
       .orElseThrow(() -> new IllegalArgumentException("No functions to combine")); 
} 

अपने प्रश्न में कोड से मेल करने के लिए, अगर आप इस तरह एक वर्ग में इस लपेट सकता है:

public class Combiner<R> { 

    private Object input; 

    public Combiner(Object input) { 
     this.input = input; 
    } 

    @SuppressWarnings("unchecked") 
    @SafeVarargs 
    public final R combineFunctions(Function<Object, Object>... functions) { 
     return (R) Arrays.stream(functions) 
         .reduce(Function::andThen) 
         .orElseThrow(() -> new IllegalArgumentException("No functions to combine")) 
         .apply(input); 
    } 

} 
+0

मुझे खेद है, लेकिन यह मेरी गलती थी - विधि को स्थैतिक नहीं होना चाहिए और मुझे लगता है कि मेरे प्रश्न में प्रदर्शित एक तरीके से * स्थिर * विधि को कार्यान्वित करना वास्तव में असंभव है (प्रश्न संपादित किया गया है)। ऐसा लगता है कि आपकी युक्तियां मुझे सही समाधान के लिए ले जाएंगी। – syntagma

+1

@REACHUS यह सिर्फ एक नमूना कोड है। विधि का कोड कक्षा के अंदर रखा जा सकता है और पाठ्यक्रम के गैर स्थैतिक संदर्भ में बुलाया जा सकता है, मेरा संपादन देखें। – Tunaki

+0

धन्यवाद, आपके द्वारा जो कोड जोड़ा गया है वह वह है जो मैं अभी अपने पास आया हूं।क्या मैं सही ढंग से समझता हूं कि इस मामले में केवल 1 स्ट्रीम बनाया जाएगा? – syntagma

3

अपने प्रश्न में उदाहरण काफी आसानी से कार्यात्मक शैली का उपयोग करके हल किया जाता है Streams। इसे हल करने के लिए "कार्यात्मक" दृष्टिकोण map संचालन के अनुक्रमों का उपयोग करके, प्रत्येक चरण को तत्वों को एक अलग प्रकार में बदलने, और वैकल्पिक रूप से परिणाम को कम करने/एकत्रित करने का है।

उदाहरण

String str = "1,2,3,4,5,6,7"; 
int max = Arrays.stream(str.split(",")).mapToInt(Integer::parseInt).max().orElse(0) 

एक ही पैटर्न "समारोह संयोजन" के अन्य प्रकार के लिए लागू होता है के लिए

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