You have a list of orders. You need orders over $100, sorted by date, mapped to customer names. Loops work but are verbose. Streams express this as a pipeline: orders.stream().filter(...).sorted(...).map(...).

Stream basics

Create and use streams.

Basics.java
import java.util.*;
import java.util.stream.*;

public class Basics {
    public static void main(String[] args) {
        List<String> raw = Arrays.asList("  Alice ", " Bob", "CHARLIE  ", "  ");

        List<String> names = raw.stream()
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .map(String::toLowerCase)
                .collect(Collectors.toList());

        System.out.println("raw:   " + raw);
        System.out.println("names: " + names);

    }
}

collection.stream() creates stream. Chain operations, end with terminal.

stream Sequence of elements supporting functional operations. Lazy until terminal.

Filter and map

Select and transform elements.

FilterMap.java
import java.util.*;
import java.util.stream.*;

public class FilterMap {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);

        int divisor = ;
        int scale = ;
        List<Integer> evensDoubled = nums.stream()
                .filter(n -> n % divisor == 0)
                .map(n -> n * scale)
                .collect(Collectors.toList());

        System.out.println("nums: " + nums);
        System.out.println("evensDoubled: " + evensDoubled);

        List<String> words = Arrays.asList("java", "stream", "api");
        List<Integer> lengths = words.stream()
                .map(String::length)
                .collect(Collectors.toList());

        System.out.println("words: " + words);
        System.out.println("lengths: " + lengths);

    }
}
import java.util.*;
import java.util.stream.*;

public class FilterMap {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);

        int divisor = ;
        int scale = ;
        List<Integer> evensDoubled = nums.stream()
                .filter(n -> n % divisor == 0)
                .map(n -> n * scale)
                .collect(Collectors.toList());

        System.out.println("nums: " + nums);
        System.out.println("evensDoubled: " + evensDoubled);

        List<String> words = Arrays.asList("java", "stream", "api");
        List<Integer> lengths = words.stream()
                .map(String::length)
                .collect(Collectors.toList());

        System.out.println("words: " + words);
        System.out.println("lengths: " + lengths);

    }
}
import java.util.*;
import java.util.stream.*;

public class FilterMap {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);

        int divisor = ;
        int scale = ;
        List<Integer> evensDoubled = nums.stream()
                .filter(n -> n % divisor == 0)
                .map(n -> n * scale)
                .collect(Collectors.toList());

        System.out.println("nums: " + nums);
        System.out.println("evensDoubled: " + evensDoubled);

        List<String> words = Arrays.asList("java", "stream", "api");
        List<Integer> lengths = words.stream()
                .map(String::length)
                .collect(Collectors.toList());

        System.out.println("words: " + words);
        System.out.println("lengths: " + lengths);

    }
}
import java.util.*;
import java.util.stream.*;

public class FilterMap {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);

        int divisor = ;
        int scale = ;
        List<Integer> evensDoubled = nums.stream()
                .filter(n -> n % divisor == 0)
                .map(n -> n * scale)
                .collect(Collectors.toList());

        System.out.println("nums: " + nums);
        System.out.println("evensDoubled: " + evensDoubled);

        List<String> words = Arrays.asList("java", "stream", "api");
        List<Integer> lengths = words.stream()
                .map(String::length)
                .collect(Collectors.toList());

        System.out.println("words: " + words);
        System.out.println("lengths: " + lengths);

    }
}

filter(predicate) keeps matching. map(function) transforms each element.

Reduce

Combine elements into single result.

Reduce.java
import java.util.*;

public class Reduce {
    public static void main(String[] args) {
        List<Integer> nums = ;

        int sum = nums.stream().reduce(0, (a, b) -> a + b);
        System.out.println("sum = " + sum);

        int product = nums.stream().reduce(1, (a, b) -> a * b);
        System.out.println("product = " + product);

        Optional<Integer> max = nums.stream().reduce((a, b) -> a > b ? a : b);
        System.out.println("max = " + max.orElse(-1));

    }
}
import java.util.*;

public class Reduce {
    public static void main(String[] args) {
        List<Integer> nums = ;

        int sum = nums.stream().reduce(0, (a, b) -> a + b);
        System.out.println("sum = " + sum);

        int product = nums.stream().reduce(1, (a, b) -> a * b);
        System.out.println("product = " + product);

        Optional<Integer> max = nums.stream().reduce((a, b) -> a > b ? a : b);
        System.out.println("max = " + max.orElse(-1));

    }
}
import java.util.*;

public class Reduce {
    public static void main(String[] args) {
        List<Integer> nums = ;

        int sum = nums.stream().reduce(0, (a, b) -> a + b);
        System.out.println("sum = " + sum);

        int product = nums.stream().reduce(1, (a, b) -> a * b);
        System.out.println("product = " + product);

        Optional<Integer> max = nums.stream().reduce((a, b) -> a > b ? a : b);
        System.out.println("max = " + max.orElse(-1));

    }
}

reduce(identity, accumulator) - sum, product, concatenation, etc.

reduce Combine stream to single value: `reduce(0, (a,b) -> a+b)` sums integers.

Sort and distinct

Order and deduplicate.

SortedDistinct.java
import java.util.*;
import java.util.stream.*;

public class SortedDistinct {
    public static void main(String[] args) {
        List<String> names = ;

        List<String> distinct = names.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println("distinct (case-sensitive): " + distinct);

        List<String> normalizedDistinct = names.stream()
                .map(String::toLowerCase)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        System.out.println("normalizedDistinct: " + normalizedDistinct);

    }
}
import java.util.*;
import java.util.stream.*;

public class SortedDistinct {
    public static void main(String[] args) {
        List<String> names = ;

        List<String> distinct = names.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println("distinct (case-sensitive): " + distinct);

        List<String> normalizedDistinct = names.stream()
                .map(String::toLowerCase)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        System.out.println("normalizedDistinct: " + normalizedDistinct);

    }
}
import java.util.*;
import java.util.stream.*;

public class SortedDistinct {
    public static void main(String[] args) {
        List<String> names = ;

        List<String> distinct = names.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println("distinct (case-sensitive): " + distinct);

        List<String> normalizedDistinct = names.stream()
                .map(String::toLowerCase)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        System.out.println("normalizedDistinct: " + normalizedDistinct);

    }
}

sorted() natural order. sorted(comparator) custom. distinct() removes duplicates.

Collectors

Gather stream results into collections.

Collectors.java
import java.util.*;
import java.util.stream.*;

public class Collectors {
    public static void main(String[] args) {
        List<String> words = ;

        String joined = words.stream()
                .map(String::toUpperCase)
                .collect(java.util.stream.Collectors.joining(", "));
        System.out.println("joined: " + joined);

        Map<Character, List<String>> byFirstLetter = words.stream()
                .collect(java.util.stream.Collectors.groupingBy(
                        w -> w.charAt(0),
                        LinkedHashMap::new,
                        java.util.stream.Collectors.toList()));
        System.out.println("byFirstLetter: " + byFirstLetter);

        Map<Character, Long> counts = words.stream()
                .collect(java.util.stream.Collectors.groupingBy(
                        w -> w.charAt(0),
                        LinkedHashMap::new,
                        java.util.stream.Collectors.counting()));
        System.out.println("counts: " + counts);

    }
}
import java.util.*;
import java.util.stream.*;

public class Collectors {
    public static void main(String[] args) {
        List<String> words = ;

        String joined = words.stream()
                .map(String::toUpperCase)
                .collect(java.util.stream.Collectors.joining(", "));
        System.out.println("joined: " + joined);

        Map<Character, List<String>> byFirstLetter = words.stream()
                .collect(java.util.stream.Collectors.groupingBy(
                        w -> w.charAt(0),
                        LinkedHashMap::new,
                        java.util.stream.Collectors.toList()));
        System.out.println("byFirstLetter: " + byFirstLetter);

        Map<Character, Long> counts = words.stream()
                .collect(java.util.stream.Collectors.groupingBy(
                        w -> w.charAt(0),
                        LinkedHashMap::new,
                        java.util.stream.Collectors.counting()));
        System.out.println("counts: " + counts);

    }
}
import java.util.*;
import java.util.stream.*;

public class Collectors {
    public static void main(String[] args) {
        List<String> words = ;

        String joined = words.stream()
                .map(String::toUpperCase)
                .collect(java.util.stream.Collectors.joining(", "));
        System.out.println("joined: " + joined);

        Map<Character, List<String>> byFirstLetter = words.stream()
                .collect(java.util.stream.Collectors.groupingBy(
                        w -> w.charAt(0),
                        LinkedHashMap::new,
                        java.util.stream.Collectors.toList()));
        System.out.println("byFirstLetter: " + byFirstLetter);

        Map<Character, Long> counts = words.stream()
                .collect(java.util.stream.Collectors.groupingBy(
                        w -> w.charAt(0),
                        LinkedHashMap::new,
                        java.util.stream.Collectors.counting()));
        System.out.println("counts: " + counts);

    }
}

collect(Collectors.toList()), toSet(), toMap(), groupingBy().

Collectors Terminal operation to gather results: `toList()`, `toMap()`, `groupingBy()`.

Exercise: Practical.java

Process sales data with stream pipeline