๐ŸŽ“ A1Learner
๐Ÿ”
0 of 40 lessons completed

Java Stream Operations

Stream operations reshape a flow or fold it into one answer. An Optional is a box that holds a value or holds nothing.

reduce folds a stream to one value

The sum fold starts from 0 and adds each number. The product fold starts from 1 and multiplies each number.

import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = List.of(2, 3, 4);
    int sum = numbers.stream().reduce(0, (a, b) -> a + b);
    int product = numbers.stream().reduce(1, (a, b) -> a * b);
    System.out.println(sum);
    System.out.println(product);
  }
}

sorted and distinct reshape the flow

distinct drops the repeated 5 and the repeated 2. sorted then prints the survivors in rising order.

import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = List.of(5, 2, 5, 8, 2, 9);
    numbers.stream()
        .distinct()
        .sorted()
        .forEach(System.out::println);
  }
}

min and max answer an Optional

The filled list gives a max that is present. The empty list gives a min that holds nothing, and orElse supplies -1.

import java.util.List;
import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    List<Integer> scores = List.of(72, 95, 61);
    Optional<Integer> max = scores.stream().max(Integer::compare);
    System.out.println(max.isPresent());
    System.out.println(max.orElse(-1));
    List<Integer> empty = List.of();
    Optional<Integer> min = empty.stream().min(Integer::compare);
    System.out.println(min.isPresent());
    System.out.println(min.orElse(-1));
  }
}

findFirst takes the first match

The first filter finds a name starting with B. The second finds no name starting with Z, and orElse supplies the word none.

import java.util.List;
import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    List<String> names = List.of("Ben", "Ana", "Bob");
    Optional<String> first = names.stream()
        .filter(name -> name.startsWith("B"))
        .findFirst();
    System.out.println(first.orElse("none"));
    Optional<String> missing = names.stream()
        .filter(name -> name.startsWith("Z"))
        .findFirst();
    System.out.println(missing.orElse("none"));
  }
}

Example

import java.util.List;
import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    List<Integer> prices = List.of(30, 10, 30, 50, 20);
    int total = prices.stream()
        .distinct()
        .reduce(0, (a, b) -> a + b);
    System.out.println(total);
    Optional<Integer> firstBig = prices.stream()
        .filter(price -> price >= 40)
        .findFirst();
    System.out.println(firstBig.orElse(-1));
  }
}

Key points

  • reduce folds a stream into one value, starting from an identity value.
  • The identity is the answer an empty stream would give for that fold.
  • sorted orders the values in the flow, and distinct drops repeated values.
  • min and max answer an Optional, because an empty stream has no extreme.
  • isPresent reports whether an Optional holds a value.
  • orElse answers a fallback value when the Optional holds nothing.
  • findFirst answers the first value of the flow as an Optional.

In this example, distinct removes the repeated 30 before reduce adds the prices into 110. A second pipeline finds the first price of 40 or more. The search answers 50 through orElse.

Note

get reads the value from an Optional, and it throws an exception when the box is empty.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What does orElse answer when an Optional holds nothing?