☕ Java (Java 21+ LTS) 🟢 Lesson 24 of 25 📂 Part 05: Collections & Capstone (Page 4 of 5) ⏱️ 25 min read

Modern Java — Lambda Expressions & Stream API Pipelines (ల్యాంబ్డా & స్ట్రీమ్స్ ఆర్కిటెక్చర్)

📌 Covered in this lesson:
Factory Conveyor Belt & Drone Remote Trigger Analogy · Functional Programming in Java 8+ · Functional Interfaces (@FunctionalInterface, Predicate, Function, Consumer, Supplier) · Lambda Expressions Syntax (->) · Method References (::) · Stream API Architecture · Intermediate vs Terminal Operations · Filtering, Mapping, Sorting, Reducing · Parallel Streams · Stock Market Trade Analytics Engine · 5 Production Pitfalls

జావా చరిత్రను Java 8 కి ముందు, Java 8 కి తర్వాత అని రెండు యుగాలుగా విభజించవచ్చు. Java 8 కు పూర్వం జావా పూర్తిగా ఇంపరేటివ్ (Imperative) ఆబ్జెక్ట్-ఓరియెంటెడ్ పద్ధతిలోనే ఉండేది; అంటే కలెక్షన్లలోని డేటాను ప్రాసెస్ చేయడానికి పెద్ద పెద్ద ఫర్ లూప్‌లు (for-loops), ఇఫ్ కండిషన్లు, మరియు టెంపరరీ లిస్ట్‌లు నింపాల్సి వచ్చేది. కానీ Java 8 లో ప్రవేశపెట్టబడిన Lambda Expressions మరియు Stream API Pipelines జావా ప్రోగ్రామింగ్ శైలిని పూర్తిగా డిక్లరేటివ్ ఫంక్షనల్ స్టైల్ (Declarative Functional Programming) లోకి మార్చేశాయి. కోడ్ సైజు 70% తగ్గిపోవడమే కాకుండా, రీడబిలిటీ మరియు మల్టీ-కోర్ ప్రాసెసర్లలో సమాంతర ప్రాసెసింగ్ (Parallel Processing) అద్భుతంగా మెరుగయ్యాయి. ఆధునిక జావా డెవలపర్ నిత్యం వాడే ల్యాంబ్దాలు, స్ట్రీమ్ ఆపరేటర్లు, మరియు బిహైండ్-ద-సీన్స్ లేజీ ఎవాల్యుయేషన్ (Lazy Evaluation) గురించి ఈ అధ్యాయంలో లోతుగా నేర్చుకుందాం.

ఫ్యాక్టరీ కన్వేయర్ బెల్ట్ & డ్రోన్ రిమోట్ ట్రిగ్గర్ అనాలజీ (The Factory Conveyor Belt & Drone Remote Trigger Analogy):

  1. 1. Lambda Expressions (డ్రోన్ రిమోట్ సింగిల్-బటన్ ట్రిగ్గర్ - Anonymous Functions): పాత రోజుల్లో ఒక పని జరగాలంటే పెద్ద Anonymous Inner Class రాసి బోలెడు బాయిలర్‌ప్లేట్ కోడ్ నింపాల్సి వచ్చేది. లాంబ్డా ఎక్స్‌ప్రెషన్ అనేది ఒక డ్రోన్ రిమోట్ కంట్రోలర్ లాంటిది. మొత్తం రిమోట్ మిషనరీని మోయకుండా, కేవలం ఒక్క బటన్ ప్రెస్ చేయగానే జరిగే పనిని మాత్రమే సంక్షిప్తంగా (param) -> action రూపంలో పంపడమే లాంబ్డా!
  2. 2. Stream API Pipelines (ఫ్యాక్టరీ కన్వేయర్ బెల్ట్ అసెంబ్లీ లైన్ - Stream Assembly Line): ఒక ఫ్యాక్టరీలో ముడి సరుకులు వేగంగా కదులుతున్న కన్వేయర్ బెల్ట్ పైకి వస్తాయి. అక్కడ వరుసగా వివిధ యంత్రాలు అమర్చబడి ఉంటాయి: మొదటి యంత్రం నాసిరకం వస్తువులను పక్కకు నెట్టివేస్తుంది (filter), రెండవ యంత్రం వస్తువులను ప్యాకింగ్ చేస్తుంది (map), మూడవ యంత్రం వాటిని సీరియల్ నంబర్ ప్రకారం క్రమపరుస్తుంది (sorted), చివరి స్టేషన్‌లో మొత్తం వస్తువులను ఒక బాక్సులో ప్యాక్ చేస్తారు (collect). ఈ మొత్తం ప్రక్రియలో ఒరిజినల్ ముడి సరుకులు ఏమాత్రం మార్పు చెందవు (Immutability).
  3. 3. Lazy Evaluation (ఆదేశం వచ్చేంతవరకు ఆన్ కాని మెషిన్లు): కన్వేయర్ బెల్ట్ చివరిలో ప్యాకింగ్ బాక్స్ (Terminal Operation) సిద్ధంగా లేకపోతే, ముందస్తు మెషిన్లు (Intermediate Operations) అసలు స్టార్ట్ కూడా కావు! జావా స్ట్రీమ్స్ సరిగ్గా అలాగే పనిచేస్తాయి — చివరి టెర్మినల్ ఆపరేషన్ పిలిచే వరకు ఒక్క లైన్ ప్రాసెసింగ్ కూడా జరగదు.

💡 ఈ పాఠంలో మీరు ఫంక్షనల్ ఇంటర్‌ఫేస్‌లు, మెథడ్ రిఫరెన్సెస్, ఫిల్టర్-మ్యాప్-రెడ్యూస్ పైప్‌లైన్‌లు మరియు రియల్-టైమ్ స్టాక్ మార్కెట్ ట్రేడ్ అనలిటిక్స్ ఇంజిన్‌ను స్వయంగా నిర్మిస్తారు!

1. ఫంక్షనల్ ప్రోగ్రామింగ్ & లాంబ్డా ఆవశ్యకత (Why Lambdas Were Introduced)

జావా ఆరంభం నుండి First-Class Functions లేని లోటు స్పష్టంగా కనిపించేది. జావాలో ఒక పనిని లేదా ప్రవర్తనను (Behavior) వేరొక మెథడ్‌కు పంపించాలంటే, తప్పనిసరిగా ఒక క్లాస్ లేదా Anonymous Inner Class సృష్టించి, ఆ క్లాస్ ఆబ్జెక్ట్‌ను పంపాల్సి వచ్చేది.

// Java 7 పాత Anonymous Inner Class విధానం (Boilerplate):
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});

// Java 8+ ఆధునిక Lambda Expression విధానం (Clean & Concise):
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));

// మరింత క్లీన్ అయిన Method Reference:
Collections.sort(names, String::compareTo);

లాంబ్డా ఎక్స్‌ప్రెషన్ వల్ల మనం ఒక ఫంక్షన్‌ను ఒక విలువలాగా (Functions as first-class citizens) ఇతర మెథడ్స్‌కు పాస్ చేయగలుగుతున్నాం.

2. Functional Interfaces (@FunctionalInterface & 4 Core Types)

కేవలం ఒకే ఒక అబ్‌స్ట్రాక్ట్ మెథడ్ (Single Abstract Method - SAM) ను కలిగి ఉండే ఇంటర్‌ఫేస్‌ను Functional Interface అంటారు. దీనిపై @FunctionalInterface అనే ఆప్షనల్ అనోటేషన్‌ను ఉంచడం ద్వారా భవిష్యత్తులో ఎవరైనా పొరపాటున రెండవ అబ్‌స్ట్రాక్ట్ మెథడ్‌ను జోడిస్తే కంపైలర్ అడ్డుకుంటుంది.

🌟 జావా 8 లోని 4 ప్రధాన ఫంక్షనల్ ఇంటర్‌ఫేస్‌లు:

1. Predicate<T>:
boolean test(T t)
ఇన్‌పుట్ తీసుకొని boolean (true/false) కండిషన్‌ను రిటర్న్ చేస్తుంది.
2. Function<T, R>:
R apply(T t)
T ఇన్‌పుట్ తీసుకొని R అవుట్‌పుట్‌గా ట్రాన్స్‌ఫార్మ్ చేస్తుంది.
3. Consumer<T>:
void accept(T t)
ఇన్‌పుట్ తీసుకుంటుంది కానీ ఏమీ రిటర్న్ చేయదు (Side-effects).
4. Supplier<T>:
T get()
ఇన్‌పుట్ తీసుకోదు, కానీ ఒక కొత్త ఆబ్జెక్ట్‌ను జనరేట్ చేస్తుంది.

3. Lambda Syntax & Method References (::)

లాంబ్డా ఎక్స్‌ప్రెషన్ యొక్క సింటాక్స్ మూడు భాగాలుగా ఉంటుంది: (parameters) -> { expression / statements }. కేవలం ఒకే పారామీటర్ ఉన్నప్పుడు బ్రాకెట్లు () ఆప్షనల్; అలాగే కేవలం సింగిల్ లైన్ స్టేట్‌మెంట్ ఉన్నప్పుడు కర్లీ బ్రేసెస్ {} మరియు return కీవర్డ్ కూడా ఆప్షనల్!

ఇప్పటికే ఉన్న మెథడ్‌ను లాంబ్డాలో నేరుగా కాల్ చేయాలనుకుంటే, మరింత క్లీన్ సింటాక్స్ అయిన Method Reference (::) ను వాడవచ్చు. ఉదాహరణకు: name -> System.out.println(name) కు బదులుగా System.out::println అని రాయవచ్చు.

4. ప్రాక్టికల్ కోడ్: Functional Interfaces & Lambdas Showcase

క్రింది జావా ప్రోగ్రామ్‌లో నాలుగు కోర్ ఫంక్షనల్ ఇంటర్‌ఫేస్‌లు మరియు మెథడ్ రిఫరెన్సెస్ వాస్తవ ఎగ్జిక్యూషన్‌లో ఎలా ప్రవర్తిస్తాయో చూడండి.

☕ Java — FunctionalInterfacesAndLambdasDemo.java
import java.util.*;
import java.util.function.*;

public class FunctionalInterfacesAndLambdasDemo {
    public static void main(String[] args) {
        System.out.println("=== 1. PREDICATE (CONDITION CHECK) ===");
        Predicate<Integer> isEligibleForLoan = score -> score >= 750;
        Predicate<Integer> isVIP = score -> score >= 820;

        System.out.println("Credit Score 780 eligible? " + isEligibleForLoan.test(780));
        System.out.println("Credit Score 720 eligible? " + isEligibleForLoan.test(720));
        // Predicate Chaining (and, or, negate)
        Predicate<Integer> eligibleNonVIP = isEligibleForLoan.and(isVIP.negate());
        System.out.println("Score 780 is Eligible Non-VIP? " + eligibleNonVIP.test(780));

        System.out.println("
=== 2. FUNCTION (TRANSFORMATION) ===");
        Function<String, Integer> parseWordLength = String::length; // Method reference
        Function<Integer, Double> calculateGST = price -> price * 1.18;

        System.out.println("Length of 'Hyderabad': " + parseWordLength.apply("Hyderabad"));
        System.out.println("Price ₹1000 + 18% GST: ₹" + calculateGST.apply(1000));

        System.out.println("
=== 3. CONSUMER (SIDE EFFECT) ===");
        Consumer<String> auditLogger = msg -> System.out.println("🔔 [AUDIT]: " + msg);
        auditLogger.accept("User 'admin' changed production configuration.");

        System.out.println("
=== 4. SUPPLIER (LAZY GENERATION) ===");
        Supplier<String> sessionTokenGenerator = () -> "TOK-" + UUID.randomUUID().toString().substring(0, 8);
        System.out.println("Generated New Token 1: " + sessionTokenGenerator.get());
        System.out.println("Generated New Token 2: " + sessionTokenGenerator.get());
    }
}
💻 Program Terminal Output:
=== 1. PREDICATE (CONDITION CHECK) ===
Credit Score 780 eligible? true
Credit Score 720 eligible? false
Score 780 is Eligible Non-VIP? true

=== 2. FUNCTION (TRANSFORMATION) ===
Length of 'Hyderabad': 9
Price ₹1000 + 18% GST: ₹1180.0

=== 3. CONSUMER (SIDE EFFECT) ===
🔔 [AUDIT]: User 'admin' changed production configuration.

=== 4. SUPPLIER (LAZY GENERATION) ===
Generated New Token 1: TOK-8B92C1D4
Generated New Token 2: TOK-4F1A3E70

5. Stream API ఆర్కిటెక్చర్ & Lazy Evaluation (స్ట్రీమ్ ఆర్కిటెక్చర్)

java.util.stream.Stream అనేది డేటా స్ట్రక్చర్ కాదు; ఇది డేటాను నిల్వ చేయదు. ఇది కలెక్షన్లు లేదా ఎరేల నుండి వచ్చే డేటా ప్రవాహాన్ని (Sequence of elements) ప్రాసెస్ చేయడానికి ఉపయోగపడే ఒక పైప్‌లైన్.

⚙️ స్ట్రీమ్ పైప్‌లైన్ యొక్క 3 ప్రధాన దశలు:

  1. 1. Source Creation: కలెక్షన్ నుండి స్ట్రీమ్ ప్రారంభించడం (list.stream() లేదా Stream.of(...)).
  2. 2. Intermediate Operations: డేటాను ఫిల్టర్ చేయడం లేదా మార్చడం (filter(), map(), sorted(), distinct()). ఇవి ఎల్లప్పుడూ Lazy గా ఉంటాయి; టెర్మినల్ ఆపరేషన్ పిలిచే వరకు ఏ పనీ చేయవు.
  3. 3. Terminal Operation: ఫలితాన్ని లెక్కించి స్ట్రీమ్‌ను ముగించడం (collect(), reduce(), count(), forEach()). టెర్మినల్ ఆపరేషన్ రన్ అయిన తర్వాత ఆ స్ట్రీమ్‌ను మళ్లీ వాడలేము (Streams cannot be reused).

6. Intermediate Operations: filter, map, flatMap, sorted & distinct

ఇంటర్మీడియట్ ఆపరేషన్లు ఒక స్ట్రీమ్‌ను తీసుకొని మరొక కొత్త స్ట్రీమ్‌ను రిటర్న్ చేస్తాయి. వీటిని ఒకదాని తర్వాత ఒకటి చైనింగ్ (Method Chaining) చేయవచ్చు:

  • filter(Predicate): షరతును సంతృప్తిపరిచే ఎలిమెంట్లను మాత్రమే అనుమతిస్తుంది.
  • map(Function): ప్రతి ఎలిమెంట్‌ను వేరొక రూపంలోకి ట్రాన్స్‌ఫార్మ్ చేస్తుంది (ఉదాహరణకు Employee నుండి జీతం తీయడం).
  • flatMap(Function): లిస్ట్‌లలోని లిస్ట్‌లను ఒకే ఫ్లాట్ స్ట్రీమ్‌గా కలుపుతుంది (Flattens nested streams).
  • sorted(Comparator): సహజ క్రమంలో లేదా నిర్దిష్ట క్రమంలో అమరుస్తుంది.
  • distinct(): equals() ఆధారంగా డూప్లికేట్లను తొలగిస్తుంది.

7. Terminal Operations: collect, reduce, count & Collectors

టెర్మినల్ ఆపరేషన్ పైప్‌లైన్‌ను ట్రిగ్గర్ చేసి అంతిమ ఫలితాన్ని ఇస్తుంది. java.util.stream.Collectors యుటిలిటీ క్లాస్ ద్వారా ఫలితాన్ని List, Set, లేదా గ్రూపింగ్ మ్యాప్‌లుగా మార్చవచ్చు:

  • collect(Collectors.toList()) లేదా ఆధునిక Java 16+ .toList(): ఫలితాన్ని లిస్ట్‌గా ఇస్తుంది.
  • collect(Collectors.groupingBy(...)): SQL GROUP BY లాగా డేటాను కేటగిరీల ప్రకారం వర్గీకరిస్తుంది.
  • reduce(initialVal, BinaryOperator): అన్ని ఎలిమెంట్లను కలిపి ఒకే విలువగా తగ్గిస్తుంది (ఉదాహరణకు మొత్తం కూడిక).
  • anyMatch(), allMatch(), noneMatch(): షార్ట్-సర్క్యూట్ బూలియన్ చెక్స్.

8. Parallel Streams & ForkJoinPool (సమాంతర ప్రాసెసింగ్)

లక్షల కొద్దీ రికార్డులను ప్రాసెస్ చేసేటప్పుడు కంప్యూటర్‌లోని అన్ని CPU కోర్లను సమానంగా ఉపయోగించడానికి parallelStream() ను పిలుస్తాము. ఇది అంతర్గతంగా JVM యొక్క కామన్ ForkJoinPool.commonPool() ని ఉపయోగించి డేటాను చిన్న చిన్న భాగాలుగా విభజించి సమాంతరంగా రన్ చేస్తుంది.

⚡ Parallel Streams గోల్డెన్ రూల్:

ఆపరేషన్లు Stateless మరియు Non-blocking గా ఉన్నప్పుడు మాత్రమే ప్యారలల్ స్ట్రీమ్స్ వాడాలి. షేర్డ్ మ్యూటబుల్ స్టేట్ ఉన్నప్పుడు లేదా I/O నెట్‌వర్క్ కాల్స్ చేసేటప్పుడు వాడితే రేస్ కండిషన్లు ఏర్పడతాయి.

9. ప్రాక్టికల్ కోడ్: Stream Pipeline Analytics Benchmark

క్రింది జావా ప్రోగ్రామ్‌లో ఎంప్లాయ్ డేటాబేస్ నుండి ఫిల్టరింగ్, సగటు జీతం లెక్కింపు, గ్రూపింగ్ బై డిపార్ట్‌మెంట్ మరియు రిడక్షన్ ఎలా సమర్థవంతంగా అమలవుతాయో పరిశీలించండి.

☕ Java — StreamPipelineAnalyticsBenchmark.java
import java.util.*;
import java.util.stream.Collectors;

public class StreamPipelineAnalyticsBenchmark {

    public record Employee(int id, String name, String dept, double salary) {}

    public static void main(String[] args) {
        System.out.println("=== STREAM PIPELINE ANALYTICS BENCHMARK ===");

        List<Employee> employees = List.of(
            new Employee(1, "Balaji", "Engineering", 125000),
            new Employee(2, "Suresh", "Product", 95000),
            new Employee(3, "Kavitha", "Engineering", 140000),
            new Employee(4, "Ramesh", "Finance", 80000),
            new Employee(5, "Anand", "Engineering", 110000),
            new Employee(6, "Divya", "Finance", 92000)
        );

        // 1. FILTER & MAP: ఇంజనీరింగ్ విభాగంలో ₹1,15,000 కంటే ఎక్కువ జీతం ఉన్నవారి పేర్లు
        List<String> topEngineers = employees.stream()
            .filter(e -> "Engineering".equals(e.dept()))
            .filter(e -> e.salary() > 115000)
            .map(Employee::name)
            .toList(); // Modern Java 16+
        System.out.println("టాప్ ఇంజనీర్లు: " + topEngineers);

        // 2. REDUCE: మొత్తం సంస్థ యొక్క శాలరీ బిల్లు
        double totalSalaryBill = employees.stream()
            .map(Employee::salary)
            .reduce(0.0, Double::sum);
        System.out.printf("మొత్తం జీతాల వ్యయం: ₹%,.2f%n", totalSalaryBill);

        // 3. GROUPING BY: డిపార్ట్‌మెంట్ వారిగా ఉద్యోగుల వర్గీకరణ
        Map<String, List<Employee>> employeesByDept = employees.stream()
            .collect(Collectors.groupingBy(Employee::dept));
        System.out.println("
--- డిపార్ట్‌మెంట్ వారిగా ఉద్యోగులు ---");
        employeesByDept.forEach((dept, list) -> 
            System.out.printf("  [%-12s] : %d ఉద్యోగులు%n", dept, list.size())
        );

        // 4. PARALLEL STREAM: సమాంతర గణన
        long highEarnersCount = employees.parallelStream()
            .filter(e -> e.salary() >= 100000)
            .count();
        System.out.println("
₹1 లక్ష కంటే ఎక్కువ జీతం ఉన్న ఉద్యోగుల సంఖ్య: " + highEarnersCount);
    }
}
💻 Program Terminal Output:
=== STREAM PIPELINE ANALYTICS BENCHMARK ===
టాప్ ఇంజనీర్లు: [Balaji, Kavitha]
మొత్తం జీతాల వ్యయం: ₹642,000.00

--- డిపార్ట్‌మెంట్ వారిగా ఉద్యోగులు ---
  [Finance     ] : 2 ఉద్యోగులు
  [Product     ] : 1 ఉద్యోగులు
  [Engineering ] : 3 ఉద్యోగులు

₹1 లక్ష కంటే ఎక్కువ జీతం ఉన్న ఉద్యోగుల సంఖ్య: 3

10. క్యాప్‌స్టోన్ ప్రాజెక్ట్: Stock Market High-Speed Trade Stream Analytics Engine

నేషనల్ స్టాక్ ఎక్స్ఛేంజ్ (NSE) లేదా NASDAQ లాంటి హై-ఫ్రీక్వెన్సీ ట్రేడింగ్ ప్లాట్‌ఫారమ్‌లలో ప్రతి మిల్లీసెకనుకు వేల కొద్దీ ట్రేడ్ ఆర్డర్లు వస్తాయి. ఈ ఆర్డర్లను ఫిల్టర్ చేసి, భారీ ట్రేడ్‌లను గుర్తించి, వాల్యూమ్‌లను సమ్మరైజ్ చేయడానికి Stream API ఒక అత్యుత్తమ టూల్. క్రింది ఎంటర్‌ప్రైజ్ ఇంజిన్ ఆర్కిటెక్చర్‌ను పరిశీలించండి:

☕ Java — StockMarketTradeStreamEngine.java
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

public class StockMarketTradeStreamEngine {

    public enum TradeType { BUY, SELL }

    // Java 21 LTS ఇమ్యూటబుల్ ట్రేడ్ రికార్డ్
    public record Trade(
        String tradeId,
        String ticker,
        TradeType type,
        double price,
        int quantity,
        Instant timestamp
    ) {
        public double getTotalValue() {
            return price * quantity;
        }
    }

    public static void main(String[] args) {
        System.out.println("=== REAL-TIME STOCK TRADE STREAM ANALYTICS ENGINE ===");

        List<Trade> tradeBook = List.of(
            new Trade("TR-101", "TCS", TradeType.BUY, 3850.50, 100, Instant.now()),
            new Trade("TR-102", "INFY", TradeType.SELL, 1520.00, 250, Instant.now()),
            new Trade("TR-103", "RELIANCE", TradeType.BUY, 2910.00, 500, Instant.now()),
            new Trade("TR-104", "TCS", TradeType.BUY, 3860.00, 200, Instant.now()),
            new Trade("TR-105", "HDFCBANK", TradeType.SELL, 1450.00, 800, Instant.now()),
            new Trade("TR-106", "RELIANCE", TradeType.SELL, 2905.00, 150, Instant.now())
        );

        System.out.println("మొత్తం ఇన్కమింగ్ ట్రేడ్ ఆర్డర్లు: " + tradeBook.size());

        // 1. ₹5,00,000 కంటే ఎక్కువ విలువైన బిగ్-బ్లాక్ ట్రేడ్స్ (Block Deals)
        System.out.println("
🔥 --- BLOCK DEALS (> ₹5,00,000) ---");
        tradeBook.stream()
            .filter(t -> t.getTotalValue() >= 500000)
            .sorted(Comparator.comparingDouble(Trade::getTotalValue).reversed())
            .forEach(t -> System.out.printf("  [%s] %-8s | %-4s | Qty: %-4d | Total: ₹%,.2f%n",
                t.tradeId(), t.ticker(), t.type(), t.quantity(), t.getTotalValue()));

        // 2. టిక్కర్ వారీగా మొత్తం ట్రేడింగ్ వాల్యూమ్ గ్రూపింగ్ (Grouping & Summing)
        System.out.println("
📊 --- TICKER WISE TOTAL TURNOVER ---");
        Map<String, Double> turnoverByTicker = tradeBook.stream()
            .collect(Collectors.groupingBy(
                Trade::ticker,
                Collectors.summingDouble(Trade::getTotalValue)
            ));

        turnoverByTicker.forEach((ticker, turnover) -> 
            System.out.printf("  Ticker: %-10s -> Turnover: ₹%,.2f%n", ticker, turnover)
        );

        // 3. మార్కెట్ సమ్మరీ గణాంకాలు (DoubleSummaryStatistics)
        DoubleSummaryStatistics stats = tradeBook.stream()
            .collect(Collectors.summarizingDouble(Trade::getTotalValue));

        System.out.println("
📈 --- LIVE MARKET METRICS ---");
        System.out.printf("కనిష్ట ట్రేడ్ విలువ (Min) : ₹%,.2f%n", stats.getMin());
        System.out.printf("గరిష్ట ట్రేడ్ విలువ (Max) : ₹%,.2f%n", stats.getMax());
        System.out.printf("సగటు ట్రేడ్ విలువ  (Avg) : ₹%,.2f%n", stats.getAverage());
        System.out.printf("మొత్తం టర్నోవర్   (Total): ₹%,.2f%n", stats.getSum());
    }
}
💻 Program Terminal Output:
=== REAL-TIME STOCK TRADE STREAM ANALYTICS ENGINE ===
మొత్తం ఇన్కమింగ్ ట్రేడ్ ఆర్డర్లు: 6

🔥 --- BLOCK DEALS (> ₹5,00,000) ---
  [TR-103] RELIANCE | BUY  | Qty: 500  | Total: ₹1,455,000.00
  [TR-105] HDFCBANK | SELL | Qty: 800  | Total: ₹1,160,000.00
  [TR-104] TCS      | BUY  | Qty: 200  | Total: ₹772,000.00

📊 --- TICKER WISE TOTAL TURNOVER ---
  Ticker: TCS        -> Turnover: ₹1,157,050.00
  Ticker: INFY       -> Turnover: ₹380,000.00
  Ticker: RELIANCE   -> Turnover: ₹1,890,750.00
  Ticker: HDFCBANK   -> Turnover: ₹1,160,000.00

📈 --- LIVE MARKET METRICS ---
కనిష్ట ట్రేడ్ విలువ (Min) : ₹380,000.00
గరిష్ట ట్రేడ్ విలువ (Max) : ₹1,455,000.00
సగటు ట్రేడ్ విలువ  (Avg) : ₹764,633.33
మొత్తం టర్నోవర్   (Total): ₹4,587,800.00

11. ప్రొడక్షన్ పిట్‌ఫాల్స్ & ఆంటీ-పాటర్న్స్ (5 Critical Production Traps)

1. Reusing an Already Consumed Stream (IllegalStateException)

జావా స్ట్రీమ్‌ను ఒకసారి టెర్మినల్ ఆపరేషన్ ద్వారా వినియోగించిన తర్వాత, దానిపై మళ్లీ మరొక ఆపరేషన్ చేయలేము! Stream<String> s = list.stream(); s.forEach(...); s.count(); అని రాస్తే తక్షణమే IllegalStateException: stream has already been operated upon or closed వస్తుంది. ప్రతిసారీ కొత్త స్ట్రీమ్‌ను తెరవాలి.

2. Side-Effects inside Intermediate Operations

stream.map(x -> externalList.add(x)) లాగా ఇంటర్మీడియట్ ఆపరేషన్లలో బయటి వేరియబుల్స్‌ను మార్చకూడదు (Side-effects). స్ట్రీమ్స్ లేజీగా ఉండటం వల్ల లేదా ప్యారలల్‌గా రన్ అయినప్పుడు డేటా అవినీతి మరియు తీవ్రమైన కన్‌కరెన్సీ బగ్స్ వస్తాయి. డేటాను కలెక్ట్ చేయడానికి collect() ని మాత్రమే వాడాలి.

3. Forgetting Terminal Operation (Ghost Pipeline Trap)

list.stream().filter(x -> x > 10); అని రాసి టెర్మినల్ ఆపరేషన్ (ఉదాహరణకు .toList()) పిలవడం మరిచిపోతే, ఆ ఫిల్టర్ కోడ్ అసలు ఎగ్జిక్యూట్ కూడా కాదు! ఎందుకంటే స్ట్రీమ్స్ Lazy గా పనిచేస్తాయి.

4. Overusing parallelStream() on Small Collections

చిన్న కలెక్షన్లపై (కొన్ని వందల ఎలిమెంట్లు ఉన్నప్పుడు) parallelStream() వాడితే, థ్రెడ్ స్విచ్చింగ్ మరియు టాస్క్ స్ప్లిట్టింగ్ ఓవర్‌హెడ్ వల్ల ప్రోగ్రామ్ మరింత స్లో అవుతుంది. మిలియన్ల కొద్దీ ఎలిమెంట్లు మరియు భారీ కంప్యూటేషన్లు ఉన్నప్పుడు మాత్రమే ప్యారలల్ స్ట్రీమ్స్ వాడాలి.

5. Mutating Captured Variables in Lambdas

లాంబ్డా ఎక్స్‌ప్రెషన్ బయటి లోకల్ వేరియబుల్స్‌ను యాక్సెస్ చేయగలదు కానీ వాటిని మార్చలేదు! ఆ వేరియబుల్స్ తప్పనిసరిగా effectively final అయి ఉండాలి (అంటే వాటి విలువ ఎక్కడా రీ-అసైన్ కాకూడదు).

12. ఇంటర్వ్యూ క్విజ్ & సెల్ఫ్-టెస్ట్ (5 Deep Interview Practice Quizzes)

జావా ల్యాంబ్దాలు మరియు స్ట్రీమ్ API పై మీ నైపుణ్యాన్ని ఈ 5 లోతైన ప్రాక్టికల్ ప్రశ్నలతో నిరూపించుకోండి. సమాధానం కోసం ప్రశ్నపై క్లిక్ చేయండి:

ప్రశ్న 1: Stream లో Lazy Evaluation అంటే ఏమిటి? ఇది పెర్ఫార్మెన్స్‌ను ఎలా పెంచుతుంది?

సమాధానం: స్ట్రీమ్ పైప్‌లైన్‌లోని ఇంటర్మీడియట్ ఆపరేషన్లు (filter, map) పైప్‌లైన్ చివరిలోని టెర్మినల్ ఆపరేషన్ (collect, findFirst) పిలిచే వరకు అసలు ఎగ్జిక్యూట్ కావు. దీనివలన జావా మొత్తం డేటాను ప్రాసెస్ చేయకుండా, అవసరమైన మొదటి ఎలిమెంట్ దొరకగానే ఆగిపోయే షార్ట్-సర్క్యూట్ (Short-circuiting) సామర్థ్యాన్ని పొందుతుంది, తద్వారా సిస్టమ్ వేగం అపారంగా పెరుగుతుంది.

ప్రశ్న 2: Functional Interface అంటే ఏమిటి? అందులో default మరియు static మెథడ్స్ ఉండవచ్చా?

సమాధానం: Functional Interface అంటే ఖచ్చితంగా కేవలం ఒకే ఒక అబ్‌స్ట్రాక్ట్ మెథడ్ (Single Abstract Method) మాత్రమే కలిగి ఉండే ఇంటర్‌ఫేస్. అయితే ఇందులో ఎన్ని default మెథడ్స్ మరియు ఎన్ని static మెథడ్స్ అయినా ఉండవచ్చు! ఎందుకంటే వాటికి బాడీ (Implementation) ఉంటుంది కాబట్టి అవి అబ్‌స్ట్రాక్ట్ కావు.

ప్రశ్న 3: map() మరియు flatMap() ల మధ్య తేడా ఏమిటి?

సమాధానం: map() అనేది 1-to-1 మ్యాపింగ్ చేస్తుంది (ఒక ఇన్‌పుట్‌కు ఒక ఔట్‌పుట్). కానీ flatMap() అనేది 1-to-Many మ్యాపింగ్ చేసి, నెస్టెడ్ కలెక్షన్లను (ఉదాహరణకు List<List<String>>) ఒకే సమాంతర స్ట్రీమ్‌గా (Flat Stream Stream<String>) చదును చేస్తుంది.

ప్రశ్న 4: జావాలో Method Reference (::) రకాలు ఎన్ని?

సమాధానం: నాలుగు రకాలు: 1) Static Method Reference (Math::max), 2) Instance Method of a particular object (System.out::println), 3) Instance Method of an arbitrary object of a particular type (String::length), 4) Constructor Reference (ArrayList::new).

ప్రశ్న 5: ఒక Stream ను ఒకసారి వాడిన తర్వాత మళ్లీ వాడటానికి ప్రయత్నిస్తే ఏమవుతుంది?

సమాధానం: జావా స్ట్రీమ్స్ కేవలం ఒకసారి మాత్రమే ప్రవహించే ఏకదిశా ప్రవాహాలు (Consumable Streams). టెర్మినల్ ఆపరేషన్ అమలు కాగానే స్ట్రీమ్ క్లోజ్ అవుతుంది. దానిని మళ్లీ వాడటానికి ప్రయత్నిస్తే JVM తక్షణమే java.lang.IllegalStateException: stream has already been operated upon or closed ఎర్రర్‌ను విసురుతుంది.

← మునుపటి పాఠం: 23. Generics & Type Safety తర్వాతి పాఠం: 25. Capstone: Banking Engine →