जावा में फंक्शनल प्रोग्रामिंग: लैम्ब्डा से Stream API तक
फंक्शनल प्रोग्रामिंग (एफपी) एक प्रतिमान है जिसमें गणनाओं को गणितीय फलनों की गणना के रूप में प्रस्तुत किया जाता है, जिसमें स्थिति में परिवर्तन और डेटा के उत्परिवर्तन से बचा जाता है। लंबे समय तक, जावा एक कड़ाई से ऑब्जेक्ट-ओरिएंटेड भाषा बनी रही, लेकिन Java 8 (2014) के आगमन के साथ, इसने लैम्ब्डा एक्सप्रेशन, फंक्शनल इंटरफेस और Stream API को जोड़कर एफपी की दिशा में एक बड़ा कदम उठाया। आज, ये उपकरण संक्षिप्त, पठनीय और समानांतर-सुरक्षित कोड लिखने के लिए अपरिहार्य हैं।
इस लेख में, हम जावा में फंक्शनल प्रोग्रामिंग की प्रमुख अवधारणाओं पर चर्चा करेंगे: लैम्ब्डा की मूल बातों से लेकर Stream API के साथ संग्रहों के उन्नत प्रसंस्करण तक। यह सामग्री उन डेवलपर्स के लिए है जो पहले से जावा के मूल सिंटैक्स से परिचित हैं, लेकिन आधुनिक दृष्टिकोणों में महारत हासिल करना चाहते हैं।
1. लैम्ब्डा एक्सप्रेशन और फंक्शनल इंटरफेस
लैम्ब्डा एक्सप्रेशन एक अनाम फलन (बिना नाम की विधि) है जिसे तर्क के रूप में पारित किया जा सकता है या एक चर में संग्रहीत किया जा सकता है। जावा में, लैम्ब्डा एक फंक्शनल इंटरफेस को लागू करता है - एक इंटरफेस जिसमें ठीक एक सार विधि (SAM - Single Abstract Method) होती है।
सिंटैक्स:
(पैरामीटर) -> { बॉडी }उदाहरण: कम्पेरेटर के लिए अनाम वर्ग बनाने के बजाय:
// पुराना तरीका (Java 7)Comparator<String> comparator = new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.length() - s2.length(); }};
// नया तरीका (Java 8+)Comparator<String> comparatorLambda = (s1, s2) -> s1.length() - s2.length();जावा में मुख्य फंक्शनल इंटरफेस (पैकेज java.util.function):
Predicate<T>- एक शर्त की जाँच करता है (विधिtest)।Function<T, R>- T प्रकार की वस्तु को R में रूपांतरित करता है (विधिapply)।Consumer<T>- वस्तु पर एक क्रिया करता है (विधिaccept)।Supplier<T>- बिना इनपुट पैरामीटर के वस्तु प्रदान करता है (विधिget)।
Predicate के साथ उदाहरण:
Predicate<Integer> isEven = n -> n % 2 == 0;System.out.println(isEven.test(4)); // trueSystem.out.println(isEven.test(5)); // falseमेथड रेफरेंस (Method References) - यह लैम्ब्डा का संक्षिप्त रूप है जब बॉडी में केवल एक विधि कॉल हो:
// लैम्ब्डाlist.forEach(item -> System.out.println(item));// मेथड रेफरेंसlist.forEach(System.out::println);2. Stream API: मुख्य संक्रियाएँ
Stream API डेटा अनुक्रमों (संग्रह, सरणियाँ, फ़ाइलें) को घोषणात्मक शैली में संसाधित करने के लिए एक शक्तिशाली उपकरण है। Stream डेटा संग्रहीत नहीं करता, बल्कि केवल संक्रियाओं की एक पाइपलाइन का वर्णन करता है। डेटा में परिवर्तन नहीं होता - प्रत्येक चरण एक नया स्ट्रीम बनाता है।
स्ट्रीम बनाना:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");Stream<String> stream = names.stream(); // अनुक्रमिकStream<String> parallelStream = names.parallelStream(); // समानांतरमध्यवर्ती संक्रियाएँ (नया Stream लौटाती हैं):
filter(Predicate)- शर्त के अनुसार तत्वों का चयन करती है।map(Function)- प्रत्येक तत्व को रूपांतरित करती है।sorted()/sorted(Comparator)- छँटाई करती है।distinct()- डुप्लिकेट हटाती है।limit(n)- तत्वों की संख्या को सीमित करती है।
टर्मिनल संक्रियाएँ (स्ट्रीम समाप्त करती हैं, परिणाम लौटाती हैं):
collect(Collectors.toList())- संग्रह में एकत्र करती है।forEach(Con