Stream Basics

 
/**
 * STREAMS IN JAVA
 * ---------------
 * Streams were introduced in Java 8 to process collections
 * in a functional and declarative style.
 * 
 * Common operations: filter, map, collect, reduce
 * 
 * Key ideas:
 *  - A stream is not a data storage (not a collection)
 *  - It works with pipelines
 *  - Supports lazy evaluation
 *  - Encurage declarative programming
 */

package com.minte9.streams.streams_basics;

import java.util.Arrays;
import java.util.List;

public class StreamsBasics {
    public static void main(String[] args) {

        List<String> names = Arrays.asList("John", "Jane", "Doe", "Julia");

        // Traditional way
        for (String name : names) {
            if (name.startsWith("J")) {
                System.out.println(name);  // John Jane Julia
            }
        }

        // Stream way
        names.stream()
             .filter(x -> x.startsWith("J"))
             .forEach(System.out::println);
    }
}

Common Operations

 
/**
 * STREAMS - MOST COMMON OPERATIONS
 * --------------------------------
 * Filter:
 *  - Select elements based on a condition (Predicate)
 * 
 * Mapping:
 *  - Transform each element into another form 
 * 
 * Sorting:
 *  - Sort elements (natural or custom comparator)
 * 
 * Collecting:
 *  - Convert stream into a collection or other result
 * 
 * Reduce:
 *  - Combine elements into a single result
 *  
 */
package com.minte9.streams.streams_basics;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CommonOperations {
    public static void main(String[] args) {
        
        // Filter
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        numbers.stream()
               .filter(n -> n % 2 == 0)
               .forEach(System.out::println);  // 2 4 6

        // Mapping   
        List<String> names = Arrays.asList("john", "jane", "jack");
        names.stream()
             .map(String::toUpperCase)
             .forEach(System.out::println);  // JOHN JANE JACK
        
        List<Integer> nums = Arrays.asList(1, 2, 3);
        int sum = nums.stream()
                      .mapToInt(Integer::intValue)
                      .sum();
        System.out.println("Sum: " + sum);  // 6

        // Sorting
        List<Integer> items = Arrays.asList(5, 2, 8, 1);
        items.stream()
             .sorted()
             .forEach(System.out::println);  // 1 2 5 8

        // Collecting
        List<String> filtered = 
            names.stream()
                 .filter(name -> name.startsWith("j"))
                 .collect(Collectors.toList());
        System.out.println(filtered);  // [john, jane, jack]

        // Reduce
        sum = numbers.stream()
                     .reduce(0, (a, b) -> a + b);
        System.out.println("Sum: " + sum);  // 21
    }
}

Iteration Styles

 
/**
 * STREAMS - ITERATION STYLES
 * --------------------------
 * Streams allow us to write collection-processing code 
 * at a higher level of abstraction.
 * 
 * TWO APPROACHES:
 * ---------------
 * External iteration (imperative):
 *  - The developer controls HOW iteration happens 
 *  - Uses loops or iterators
 *  - Requires mutable state (counter, variables)
 * 
 * Internal iteration (declarative):
 *  - The library controls HOW iteration hapens
 *  - The developer specifies WHAT should be done
 *  - No explicit loops or mutable counters
 * 
 * Iterator - external iterator
 * Stream   - internal iterator
 */

package com.minte9.streams.streams_basics;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class IterationStyles {
    public static void main(String[] args) {
        
        List<Integer> numbers = Arrays.asList(1, 2, 3);
        int count;

        // External iteration (for-each loop)
        count = 0;
        for (int n : numbers) {
            if (n <= 2) {
                count++;
            }
        }
        System.out.println(count);  // 2

        // External iteration (Iterator)
        count = 0;
        Iterator<Integer> it = numbers.iterator();
        while(it.hasNext()) {
            int n = it.next();
            if (n <= 2) {
                count++;
            }
        }
        System.out.println(count);  // 2

        // Internal iteration - Stream
        long total = 
            numbers.stream()
                   .filter(n -> n <= 2)
                   .count();
        System.out.println(total);  // 2
    }    
}

Laziness

 
/**
 * STREAMS - LAZY EVALUATION
 * -------------------------
 * Streams are evaluated lazily.
 * 
 * KEY IDEAS:
 * ----------
 *  - A stream does NOT process data when it is created
 *  - Intermediate operations (filter, map) are lazy
 *  - Nothing happens until a TERMINAL operation is invoked
 * 
 * TERMINAL OPERATIONS:
 * --------------------
 *  - count()
 *  - forEach()
 *  - collect()
 *  - findFirst()
 *  - anyMatch()
 * 
 * Without a terminal operation, a stream does nothing.
 * 
 * When we write numbers.strea().filter(...) we are only 
 * describing a pipeline.
 */

package com.minte9.streams.streams_basics;

import java.util.Arrays;
import java.util.List;

public class Laziness {
    public static void main(String[] args) {
        
        List<Integer> numbers = Arrays.asList(1, 2, 3);

        // No terminal operation - nothing happens (no output)
        numbers.stream()
               .filter(n -> {
                    System.out.println("filter: " + n);
                    return n <= 2;
               });

        // Terminal operation triggers evaluation
        numbers.stream()
               .filter(n -> {
                    System.out.println("filter: " + n);
                    return n <= 2;
               })
               .count();  // Output: 1 2 3      
    }
}




References: