2013-11-26 9 views
5

मैं अगर किसी को भी ठूंठ/लैम्ब्डा की दृश्यता बनाने के बिना एक लैम्ब्डा के अंदर एक तर्क उपहास करने के लिए एक रास्ता खोजने सोच रहा था?जावा 8 lambdas के लिए यूनिट परीक्षण

public List<Item> processFile(String fileName) { 
    // do some magic.. 
    Function<String, List<String>> reader = (fileName) -> { 
     List<String> items = new ArrayList<>(); 
     try (BufferedReader br = new BufferedReader(new FileReader(fileName))) { 
      String output; 
      while ((output = br.readLine()) != null) { 
      items.add(output); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    return items; 
    }; 

    List<String> lines = reader.apply("file.csv"); 
    // do some more magic.. 
} 
+0

एक लैम्ब्डा किसी और चीज की तरह एक संदर्भ लोड कर सकता है (यदि आप इसके अंदर स्टब करना चाहते हैं)। लेकिन सावधान रहें कि चर को कैप्चर किए बिना लैम्ब्डा सबसे अधिक संभावना सिंगलटन होगा। पैरामीटर के रूप में फ़ंक्शन में गुजरने की संभावित उपयोगी तकनीक के लिए – aepurniet

उत्तर

9

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

मैं कहेंगे कि Andrey Chaschev's answer जो निर्भरता parameterizing पता चलता है एक अच्छा एक है और शायद कुछ स्थितियों में लागू होता है। तो, इसके लिए +1। इस पर

public List<Item> processFile(
    String fileName, 
    Function<String, BufferedReader> toReader, 
    Function<BufferedReader, List<String>> toStringList, 
    Function<List<String>, List<Item>> toItemList) 
{ 
    List<String> lines = null; 
    try (BufferedReader br = toReader.apply(fileName)) { 
     lines = toStringList.apply(br); 
    } catch (IOException ioe) { /* ... */ } 

    return toItemList.apply(lines); 
} 

एक जोड़े टिप्पणियों, हालांकि: एक इस प्रक्रिया को जारी रख सकता है और छोटे टुकड़ों में प्रसंस्करण टूट, इसलिए पसंद है। सबसे पहले, इस प्रश्न के लिखित रूप में काम नहीं करता है, के बाद से विभिन्न lambdas परेशान IOExceptions फेंक, जो जाँच कर रहे हैं, और Function प्रकार है कि अपवाद फेंक घोषित नहीं किया गया है। दूसरा यह है कि आपको इस समारोह में गुंबदों को गुजरना पड़ता है। हालांकि यह काम नहीं करता है (चेक अपवादों के कारण) मैंने इसे लिखा:

void processAnActualFile() { 
    List<Item> items = processFile(
     "file.csv", 
     fname -> new BufferedReader(new FileReader(fname)), 
       // ERROR: uncaught IOException 
     br -> { 
      List<String> result = new ArrayList<>(); 
      String line; 
      while ((line = br.readLine()) != null) { 
       result.add(line); 
      } 
      return result; 
     },  // ERROR: uncaught IOException 
     stringList -> { 
      List<Item> result = new ArrayList<>(); 
      for (String line : stringList) { 
       result.add(new Item(line)); 
      } 
      return result; 
     }); 
} 

उह! मुझे लगता है कि मैंने नई कोड गंध की खोज की है:

यदि आपको लैम्ब्डा के अंदर एक लूप या लूप-लूप लिखना है, तो आप कुछ गलत कर रहे हैं।

कुछ बातें यहाँ पर जा रहे हैं। सबसे पहले, मैं/हे पुस्तकालय वास्तव में कार्यान्वयन (InputStream, Reader, BufferedReader) कि कसकर युग्मित के विभिन्न टुकड़ों से बना है। उन्हें अलग करने की कोशिश करने के लिए वास्तव में उपयोगी नहीं है। दरअसल, पुस्तकालय ताकि है कि आप के लिए पैर काम का एक गुच्छा संभाल (जैसे NIO Files.readAllLines के रूप में) कुछ सुविधा उपयोगिताओं हैं विकसित किया गया है।

अधिक महत्वपूर्ण बात यह है कि डिजाइनिंग फ़ंक्शंस जो स्वयं के बीच मूल्यों के योग (सूचियों) को पास करते हैं, और इन कार्यों को लिखते हैं, वास्तव में जाने का गलत तरीका है। यह हर फंक्शन को इसके अंदर एक लूप लिखना पड़ता है। हम वास्तव में क्या करना चाहते हैं वह लिखना है जो प्रत्येक एक ही मूल्य पर काम करता है, और उसके बाद जावा 8 में नई स्ट्रीम लाइब्रेरी को हमारे लिए एकत्रीकरण का ख्याल रखना चाहिए।

टिप्पणी द्वारा वर्णित कोड से निकालने के लिए मुख्य कार्य "कुछ और जादू करें" जो List<String> को List<Item> में परिवर्तित करता है। हम इस तरह, अभिकलन कि एकString धर्मान्तरित एक Item में निकालना चाहते हैं:

class Item { 
    static Item fromString(String s) { 
     // do a little bit of magic 
    } 
} 

बार जब आप इस किया है, तो आप स्ट्रीम और NIO पुस्तकालयों आप के लिए काम का एक गुच्छा करते हैं कर सकते हैं:

public List<Item> processFile(String fileName) { 
    try (Stream<String> lines = Files.lines(Paths.get(fileName))) { 
     return lines.map(Item::fromString) 
        .collect(Collectors.toList()); 
    } catch (IOException ioe) { 
     ioe.printStackTrace(); 
     return Collections.emptyList(); 
    } 
} 

(ध्यान दें कि इस छोटी विधि का अधिक आधा IOException से निपटने के लिए है।)

अब यदि आप कुछ यूनिट परीक्षण करना चाहते हैं, तो आपको वास्तव में परीक्षण करने की आवश्यकता है जो जादू का थोड़ा सा है। तो आप इसे एक अलग धारा पाइप लाइन में लपेट कर देते हैं:

void testItemCreation() { 
    List<Item> result = 
     Arrays.asList("first", "second", "third") 
       .stream() 
       .map(Item::fromString) 
       .collect(Collectors.toList()); 
    // make assertions over result 
} 

(वास्तव में, यहां तक ​​कि इस नहीं बहुत सही है आप किसी एक Item में एक पंक्ति परिवर्तित करने के लिए इकाई परीक्षण लिखने के लिए चाहते हैं लेकिन।। हो सकता है आप कुछ परीक्षण डाटा कहीं है, तो आप इसे इस तरह मदों की एक सूची में बदलने का था, और फिर सूची में जिसके परिणामस्वरूप वस्तुओं के संबंध में वैश्विक दावे करते हैं।)


मैं फिरते गए लैम्बडा को अलग करने के तरीके के बारे में आपके मूल प्रश्न से बहुत दूर। कृपया मुझे खुद को शामिल करने के लिए क्षमा करें।

मूल उदाहरण में लैम्ब्डा बहुत दुर्भाग्यपूर्ण है क्योंकि जावा I/O पुस्तकालय काफी बोझिल हैं, और एनआईओ लाइब्रेरी में नए एपीआई हैं जो उदाहरण को एक लाइनर में बदल देते हैं।

फिर भी, यहां सबक यह है कि समेकित प्रक्रियाओं को लिखने के बजाय, अलग-अलग मूल्यों को संसाधित करने वाले कार्यों को लिखें, और धाराओं को एकत्रीकरण को संभालने दें। इस तरह, एक जटिल लैम्ब्डा के बिट्स का मज़ाक उड़ाकर परीक्षण करने के बजाय, आप विभिन्न तरीकों से स्ट्रीम पाइपलाइनों को एक साथ जोड़कर परीक्षण कर सकते हैं।

3

मुझे यकीन है कि अगर आप क्या कह रहे हैं, लेकिन यदि आप किसी अन्य वर्ग के लिए लैम्ब्डा अर्थात से एक लैम्ब्डा निकालने या के रूप में है और एक पैरामीटर के रूप में यह गुजारें सकता नहीं हूँ। एक उदाहरण में नीचे मैं पाठक सृजन नकली:

public static void processFile(String fileName, Function<String, BufferedReader> readerSupplier) { 
    // do some magic.. 
    Function<String, List<String>> reader = (name) -> { 
     List<String> items = new ArrayList<>(); 
     try(BufferedReader br = readerSupplier.apply(name)){ 
      String output; 
      while ((output = br.readLine()) != null) { 
       items.add(output); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     return items; 
    }; 

    List<String> lines = reader.apply(fileName); 
    // do some more magic.. 
} 

public static void main(String[] args) { 
    // mocked call 
    processFile("file.csv", name -> new BufferedReader(new StringReader("line1\nline2\n"))); 

    //original call 
    processFile("1.csv", name -> { 
     try { 
      return new BufferedReader(new FileReader(name)); 
     } catch (FileNotFoundException e) { 
      throw new RuntimeException(e); 
     } 
    }); 
} 
+0

+1। –

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