Introduction to Java Streams: Pipeline Processing Since Java 8
Introduction to Java Streams: Pipeline Processing
Java 8 के बाद से Stream API ने data processing को एकदम आसान और modern बना दिया है। पहले जहाँ हमें collections या arrays को manually iterate करना पड़ता था, वहीं अब Streams के ज़रिए हम data को एक pipeline की तरह process कर सकते हैं। इसका मतलब है कि data एक flow में जाता है और हर step पर उस पर कोई न कोई operation perform होता है।
Stream API का main purpose है कि data processing को readable, fast और efficient बनाया जाए — बिना boilerplate code के। अब loop या iterator के झंझट में पड़ने की ज़रूरत नहीं है, बस data pipeline बना दो और result अपने आप मिल जाएगा।
What is Java Stream?
Java Stream एक sequence of data elements है जो functional style में process होते हैं। Stream खुद data store नहीं करता, बल्कि collection या array से data लेकर उस पर operations perform करता है। इसे आप data की flowing river की तरह समझ सकते हो — जहाँ हर stage पर कुछ processing होती रहती है।
Streams के operations दो तरह के होते हैं — intermediate और terminal। Intermediate operations data को modify या transform करते हैं, जबकि terminal operation result produce करता है।
Example of Basic Stream
import java.util.*;
class Example {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.forEach(System.out::println);
}
}
ऊपर दिए गए example में list के even numbers को filter किया गया, फिर उनका square लेकर print किया गया। यही कहलाता है pipeline processing — एक continuous flow में data transformations।
Why Use Java Streams?
Streams को use करने के कई benefits हैं जो traditional iteration methods से कहीं बेहतर हैं।
- Readable Code: Stream API का syntax काफी clean और expressive होता है।
- Less Boilerplate: Loop या iterator की जरूरत नहीं पड़ती।
- Parallel Processing: Multicore processors का फायदा उठाने के लिए parallel streams का use कर सकते हैं।
- Functional Approach: Stream API functional programming concept को Java में लाता है।
Stream Pipeline Concept
Stream pipeline तीन main components से मिलकर बनी होती है:
- Source: कोई collection, array या I/O channel जो data provide करता है।
- Intermediate Operations: जैसे filter(), map(), sorted() — ये data को modify करते हैं लेकिन new stream return करते हैं।
- Terminal Operation: जैसे collect(), forEach(), count() — ये result produce करते हैं और pipeline को terminate करते हैं।
Pipeline Example
List<String> names = Arrays.asList("Amit", "Rahul", "Priya", "Anjali");
names.stream()
.filter(name -> name.startsWith("A"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
यहाँ पर data source है list, फिर filter() से सिर्फ "A" से शुरू होने वाले नाम निकाले गए, फिर map() से uppercase किया गया, sorted() से order में लाया गया और अंत में forEach() से print किया गया।
Characteristics of Java Streams
Stream API की कुछ खास विशेषताएँ हैं जो इसे powerful बनाती हैं:
- Statelessness: Intermediate operations stateless होती हैं यानी हर element independently process होता है।
- Lazy Evaluation: Intermediate operations तब तक execute नहीं होती जब तक कोई terminal operation call न हो।
- Non-reusable: एक बार stream use हो जाने पर उसे दोबारा use नहीं किया जा सकता।
- Possibility of Parallelism: Streams को parallel mode में run किया जा सकता है जिससे performance बेहतर होती है।
Types of Streams
Java में Streams दो प्रकार की होती हैं:
| Type | Description |
|---|---|
| Sequential Stream | Default stream जो elements को एक thread में process करती है। |
| Parallel Stream | Multiple threads में elements को parallel process करती है। Performance बढ़ाने के लिए useful। |
Example of Parallel Stream
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
list.parallelStream()
.forEach(System.out::println);
Parallel stream में order unpredictable हो सकता है क्योंकि processing multi-threaded होती है।
Stream Operations in Detail
1. filter()
यह method condition के आधार पर elements को filter करता है। Example:
list.stream().filter(n -> n > 10)
2. map()
यह method elements को transform करता है। Example:
list.stream().map(n -> n * 2)
3. sorted()
यह method elements को ascending या descending order में sort करता है।
4. distinct()
यह duplicate elements को remove करता है।
5. limit() और skip()
limit() पहले N elements return करता है जबकि skip() पहले N elements को ignore करता है।
6. collect()
यह terminal operation है जो result को List, Set या Map में convert करता है।
Example of collect()
List<Integer> evenNumbers = list.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
Stream vs Collection
| Parameter | Stream | Collection |
|---|---|---|
| Storage | Data store नहीं करता | Data store करता है |
| Nature | Lazy evaluation | Eager evaluation |
| Reusability | Re-usable नहीं | Re-usable है |
| Processing | Functional style | Iterative style |
Creating Streams
- From Collection:
list.stream() - From Arrays:
Arrays.stream(array) - Using Stream.of():
Stream.of("A", "B", "C") - From Files:
Files.lines(Paths.get("data.txt"))
Primitive Streams
Java Stream API primitive types के लिए भी specialized streams provide करता है ताकि boxing/unboxing overhead कम हो।
| Stream Type | Data Type | Example |
|---|---|---|
| IntStream | int | IntStream.range(1, 5) |
| LongStream | long | LongStream.of(1L, 2L, 3L) |
| DoubleStream | double | DoubleStream.of(1.5, 2.5) |
Stream Short-circuiting Operations
कुछ operations पूरे stream को process नहीं करते, बल्कि result मिलते ही execution रोक देते हैं। जैसे:
- findFirst() – पहला matching element return करता है।
- findAny() – कोई भी एक matching element return करता है।
- anyMatch(), allMatch(), noneMatch() – Predicate के base पर boolean result देते हैं।
Example:
boolean hasEven = list.stream().anyMatch(n -> n % 2 == 0);
Reduction Operations
Reduction operations का use पूरे stream को एक single result में reduce करने के लिए किया जाता है। जैसे sum, average या concatenate करना।
Example:
int sum = list.stream().reduce(0, (a, b) -> a + b);
Best Practices for Using Streams
- Complex logic के लिए Streams का overuse न करें।
- Performance-critical code में parallel stream का use carefully करें।
- Stream को दोबारा reuse करने की कोशिश न करें।
- Debugging के लिए
peek()का उपयोग करें।
Example of peek()
list.stream()
.peek(System.out::println)
.filter(n -> n > 10)
.count();
Real-Life Use Cases
- Data Filtering: बड़े datasets से specific records निकालना।
- Aggregation: Sum, average या count निकालना।
- File Processing: Lines को read करके filter करना।
- Database Stream: JDBC से data fetch करके process करना।
Summary of Java Streams
- Stream API functional programming का best example है।
- यह readable, efficient और concise code लिखने में help करता है।
- Pipeline processing data transformation को आसान बनाता है।
- Parallel streams performance को improve करती हैं।
- Exam के point of view से, Stream API Java 8 का सबसे important topic है।