Lesson 10 of 13

Lambdas & the Stream API

Learn and the Stream , which let you write many as a short of steps such as filter, map and collect.

Java
import java.util.function.*;

// A lambda is a compact implementation of a single-method interface.
Runnable task            = () -> System.out.println("running");
Function<String, Integer> len = s -> s.length();
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
Predicate<String> isEmpty     = String::isEmpty;      // method reference
Supplier<List<String>> maker   = ArrayList::new;      // constructor reference
Consumer<String> printer       = System.out::println;

// The core functional interfaces you will meet constantly:
//   Function<T,R>   R apply(T)      transform
//   Predicate<T>    boolean test(T) filter
//   Consumer<T>     void accept(T)  side effect
//   Supplier<T>     T get()         produce
//   UnaryOperator<T>  Function<T,T>

System.out.println(len.apply("hello"));       // 5
System.out.println(add.apply(2, 3));          // 5

// Composition
Function<Integer, Integer> doubled = x -> x * 2;
Function<Integer, Integer> plusTen = x -> x + 10;
System.out.println(doubled.andThen(plusTen).apply(5));   // 20
System.out.println(doubled.compose(plusTen).apply(5));   // 30
Java
import java.util.*;
import java.util.stream.*;

record Order(String customer, String region, double total, int items) {}

List<Order> orders = List.of(
    new Order("Ada",  "EU", 120.50, 3),
    new Order("Bob",  "US",  45.00, 1),
    new Order("Cleo", "EU", 310.75, 8),
    new Order("Dan",  "US", 210.00, 4),
    new Order("Ada",  "EU",  60.25, 2)
);

// Filter -> map -> collect
List<String> bigEuCustomers = orders.stream()
    .filter(o -> o.region().equals("EU"))
    .filter(o -> o.total() > 100)
    .map(Order::customer)
    .distinct()
    .sorted()
    .toList();                                   // [Ada, Cleo]

// Reductions
double revenue   = orders.stream().mapToDouble(Order::total).sum();
OptionalDouble avg = orders.stream().mapToDouble(Order::total).average();
Optional<Order> biggest = orders.stream().max(Comparator.comparingDouble(Order::total));

System.out.println(revenue);                     // 746.5
System.out.println(biggest.map(Order::customer).orElse("none"));   // Cleo

// Sorting by several keys
List<Order> sorted = orders.stream()
    .sorted(Comparator.comparing(Order::region)
                      .thenComparing(Comparator.comparingDouble(Order::total).reversed()))
    .toList();
Java
import java.util.*;
import java.util.stream.*;

// Collectors do the heavy lifting for grouping and summarising.
Map<String, List<Order>> byRegion = orders.stream()
    .collect(Collectors.groupingBy(Order::region));

Map<String, Double> revenueByRegion = orders.stream()
    .collect(Collectors.groupingBy(Order::region,
             Collectors.summingDouble(Order::total)));
// {EU=491.5, US=255.0}

Map<Boolean, List<Order>> split = orders.stream()
    .collect(Collectors.partitioningBy(o -> o.total() >= 100));

String names = orders.stream()
    .map(Order::customer)
    .distinct()
    .collect(Collectors.joining(", ", "[", "]"));   // [Ada, Bob, Cleo, Dan]

DoubleSummaryStatistics stats = orders.stream()
    .collect(Collectors.summarizingDouble(Order::total));
System.out.println(stats.getMax() + " " + stats.getCount());

// flatMap flattens nested structures
List<List<String>> tags = List.of(List.of("a", "b"), List.of("c"));
List<String> flat = tags.stream().flatMap(List::stream).toList();  // [a, b, c]

// Generating streams
List<Integer> firstTen = Stream.iterate(1, n -> n + 1).limit(10).toList();
IntStream.rangeClosed(1, 5).forEach(System.out::println);
Finished reading?Mark it done to track your progress.

Tip: use the ← and → keys to move between lessons.