2015-08-25 13 views
30

गठबंधन करने के लिए समारोह वस्तु के रूप में इस्तेमाल संदर्भ वहाँ अपने तरीकों का उपयोग करने के लिए एक Function वस्तु के रूप में एक विधि संदर्भ का उपयोग करने के Java8 में एक रास्ता है:Java8 विधि कार्यों

Stream.of("ciao", "hola", "hello") 
    .map(String::length.andThen(n -> n * 2)) 

इस सवाल से संबंधित नहीं है

Stream.of("ciao", "hola", "hello").map(String::length).map(n -> n * 2); 
+0

इनपुट और वांछित आउटपुट प्रदान करें, फिर आपको बताएगा कि जावा 8 स्ट्रीम के साथ कैसे कार्यान्वित किया जाए। – Alboz

+4

यह स्ट्रीम एपीआई से संबंधित नहीं है, यह विधि संदर्भ – rascio

+1

से संबंधित है। कैनोलिक समाधान '.map (s -> s.length() * 2)' है क्योंकि इसे तुरंत दोबारा जोड़ने के लिए इसे दो कार्यों के रूप में व्यक्त करने का कोई कारण नहीं है। यदि आपके पास पहले से मौजूद 'फ़ंक्शन' उदाहरण है या बाद में पुन: उपयोग के लिए उनमें से कम से कम एक को रखना चाहते हैं, तो समस्या तब मौजूद नहीं है जब आपके पास कोई ऑब्जेक्ट हो जिसे आप 'और फिर' या 'लिखें' पर आक्रमण कर सकते हैं। अन्य सभी मामलों में, जटिल होने का कोई कारण नहीं है। – Holger

उत्तर

27

आप यह करने के लिए एक स्थिर विधि लिख सकते हैं:

import java.util.function.*; 

class Test { 
    public static void main(String[] args) { 
     Function<String, Integer> function = combine(String::length, n -> n * 2); 
     System.out.println(function.apply("foo")); 
    } 

    public static <T1, T2, T3> Function<T1, T3> combine(
     Function<T1, T2> first, 
     Function<T2, T3> second) { 
     return first.andThen(second); 
    } 
} 

फिर आप एक उपयोगिता में रख सकता है कक्षा और इसे स्थिर रूप से आयात करें।

import java.util.function.*; 

class Test { 
    public static void main(String[] args) { 
     Function<String, Integer> function = asFunction(String::length).andThen(n -> n * 2); 
     System.out.println(function.apply("foo")); 
    } 

    public static <T1, T2> Function<T1, T2> asFunction(Function<T1, T2> function) { 
     return function;  
    } 
} 
+3

दूसरे के लिए +1, अगर यह वास्तव में केवल कास्ट से बचने के बारे में है (मैं केवल 'एफएन (स्ट्रीम :: लंबाई)' सुझाव देने जा रहा था) –

+0

स्थिर विधि बनाने की कोई आवश्यकता नहीं है। नीचे जेबी निजेट द्वारा जवाब देखें। – pvillela

+0

@ पविलला: सच (हालांकि तब आपके पास एक अलग चर है अनावश्यक रूप से, या बदसूरत कास्ट)। इसे यहां छोड़ देगा ताकि सभी विकल्प उपलब्ध हों। –

4

आप लिख सकते हैं करना चाहते हैं बस इसे एक चर में बचा सकते हैं:

Function<String, Integer> toLength = String::length; 
Stream.of("ciao", "hola", "hello") 
     .map(toLength.andThen(n -> n * 2)); 

या आप एक डाली उपयोग कर सकते हैं, लेकिन यह भी कम पठनीय है, IMO:

Stream.of("ciao", "hola", "hello") 
     .map(((Function<String, Integer>) String::length).andThen(n -> n * 2)); 
+0

मुझे पता है लेकिन कभी-कभी मैं फ़ंक्शंस को जोड़ना चाहता हूं ... – rascio

+1

यह 'स्ट्रीम' एपीआई के बारे में नहीं है ... – rascio

17

आप: Stream, यह सिर्फ उदाहरण के रूप में प्रयोग किया जाता है, मैं विधि संदर्भ के बारे में जवाब

10

आप को प्राप्त करने के लिए आप क्या डाले उपयोग करके इनलाइन चाहते सक्षम होना चाहिए:

Stream.of("ciao", "hola", "hello") 
     .map(((Function<String, Integer>) String::length).andThen(n -> n * 2)) 

वहाँ केवल संकलक के लिए 'प्रकार संकेत' हैं, इसलिए वे नहीं वास्तव में वस्तु 'डाली' करते हैं और एक वास्तविक कलाकारों के भूमि के ऊपर नहीं है।


वैकल्पिक रूप से, आप पठनीयता के लिए एक स्थानीय चर का उपयोग कर सकते हैं:

Function<String, Integer> fun = String::length 

Stream.of("ciao", "hola", "hello") 
     .map(fun.andThen(n -> n * 2)); 

एक तीसरा रास्ता है कि अधिक संक्षिप्त हो सकता है एक उपयोगिता विधि के साथ है:

public static <T, X, U> Function<T, U> chain(Function<T, X> fun1, Function<X, U> fun2) 
{ 
    return fun1.andThen(fun2); 
} 

Stream.of("ciao", "hola", "hello") 
     .map(chain(String::length, n -> n * 2)); 

कृपया ध्यान दें कि यह परीक्षण नहीं किया गया है, इस प्रकार मुझे नहीं पता कि इस मामले में टाइप अनुमान सही तरीके से काम करता है या नहीं।

+0

तो, चीनी सिंटेक्स नहीं है, यह बिना किसी कलाकार और कोष्ठक के इनलाइन है ... thx – rascio

+0

मेरा संपादन देखें एक और उदाहरण के लिए। – Clashsoft

5

तुम एक डाली उपयोग कर सकते हैं

Stream.of("ciao", "hola", "hello") 
     .map(((Function<String, Integer>) String::length) 
       .andThen(n -> n * 2)) 
     .forEach(System.out::println); 

प्रिंट

8 
8 
10 
6

तुम भी

Function.identity().andThen(String::length).andThen(n -> n * 2) 
उपयोग कर सकते हैं:

वैकल्पिक रूप से, यह जानकर आप क्या कर रहे एक सरल तरीका है जिसके स्थिर सिर्फ समारोह में यह दिया है देता है, संकलक की खातिर बनाने

समस्या है, String::length आवश्यक नहीं है Function; यह कई कार्यात्मक इंटरफेस के अनुरूप हो सकता है। इसका उपयोग उस संदर्भ में किया जाना चाहिए जो लक्ष्य प्रकार प्रदान करता है, और संदर्भ हो सकता है - असाइनमेंट, विधि आमंत्रण, कास्टिंग।Function सिर्फ लक्ष्य टाइपिंग के लिए एक स्थिर विधि प्रदान कर सकता है

, तो हम

Function.by(String::length).andThen(n->n*2) 

static <T, R> Function<T, R> by(Function<T, R> f){ return f; } 

उदाहरण के लिए, मैं a functional interface

static <T> AsyncIterator<T> by(AsyncIterator<T> asyncIterator) 

में इस तकनीक का प्रयोग कर सकता है एक लैम्ब्डा अभिव्यक्ति या विधि संदर्भ से एक AsyncIterator बनाने के लिए सिंटेक्स चीनी।

यह विधि केवल asyncIterator तर्क देता है, जो थोड़ा अजीब लगता है। स्पष्टीकरण:

के बाद से AsyncIterator एक कार्यात्मक इंटरफ़ेस है, एक उदाहरण 3 संदर्भों में एक लैम्ब्डा अभिव्यक्ति या एक विधि संदर्भ, द्वारा बनाया जा सकता:

// Assignment Context 
AsyncIterator<ByteBuffer> asyncIter = source::read; 
asyncIter.forEach(...); 

// Casting Context 
((AsyncIterator<ByteBuffer>)source::read) 
    .forEach(...); 

// Invocation Context 
AsyncIterator.by(source::read) 
    .forEach(...); 

3 विकल्प अन्य की तुलना में बेहतर लग रहा है दो, और यह इस विधि का उद्देश्य है।

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