Логотип Workflow

Article

Stream Api And Optional

Topic 10. Stream API, Optional

Stream API and Optional solve two frequent problems:

  1. expressing data transformations as readable pipelines,
  2. handling absence of values explicitly.

Stream API model

A Stream is not a data container. It is a computation pipeline over data source.

Key properties:

  • stream does not own storage,
  • source collection is usually not mutated,
  • intermediate operations are lazy,
  • execution starts at terminal operation.

Stream pipeline

Pipeline structure

  1. Source: list.stream(), Stream.of(...), Files.lines(...).
  2. Intermediate operations: filter, map, flatMap, sorted, distinct, limit.
  3. Terminal operation: toList, collect, reduce, count, forEach, findFirst.

Example 1. Filter + map + sort

List<String> names = List.of("ann", "bob", "alex", "anna");

List<String> result = names.stream()
        .filter(n -> n.length() > 3)
        .map(String::toUpperCase)
        .sorted()
        .toList();

System.out.println(result); // [ALEX, ANNA]

Example 2. Aggregation (reduce, collectors)

List<Integer> prices = List.of(100, 250, 80, 70);

int total = prices.stream()
        .reduce(0, Integer::sum);

double avg = prices.stream()
        .collect(java.util.stream.Collectors.averagingInt(Integer::intValue));

System.out.println(total); // 500
System.out.println(avg);   // 125.0

Example 3. Flatten nested data with flatMap

List<List<String>> tags = List.of(
        List.of("java", "backend"),
        List.of("backend", "spring")
);

List<String> unique = tags.stream()
        .flatMap(List::stream)
        .distinct()
        .sorted()
        .toList();

System.out.println(unique); // [backend, java, spring]

Laziness

Stream<String> s = names.stream().filter(n -> n.startsWith("a"));
// no real execution yet
long count = s.count();

Lazy model allows JVM optimization and avoids unnecessary work.

When streams are good vs when loops are better

Streams fit when:

  1. transformation steps are linear,
  2. filtering + aggregation dominate,
  3. side effects are minimal.

Loops can be better when:

  1. branching logic is complex,
  2. step-by-step debugging is critical,
  3. hot-path imperative code is clearer.

Parallel streams

parallelStream() may help CPU-bound workloads, but not always.

Use cautiously:

  • avoid shared mutable state inside lambdas,
  • account for parallelization overhead,
  • measure before adopting.

Optional: explicit absence contract

Optional<T> means value may or may not be present.

Optional<String> email = findEmailByUserId(10L);
String value = email.orElse("[email protected]");

This forces explicit caller handling instead of hidden null assumptions.

Core Optional operations

  • isPresent, isEmpty,
  • orElse, orElseGet, orElseThrow,
  • map, flatMap, filter,
  • ifPresent, ifPresentOrElse.

Example 4. Null-safe chain

Optional<User> user = findUser(id);
String city = user
        .map(User::getAddress)
        .map(Address::getCity)
        .filter(c -> !c.isBlank())
        .orElse("Unknown");

orElse vs orElseGet

String a = opt.orElse(expensiveFallback());           // always evaluates fallback
String b = opt.orElseGet(() -> expensiveFallback());  // lazy fallback

For expensive fallback logic, prefer orElseGet.

Where Optional is useful and where it is not

Useful:

  1. service/repository return values that may be missing,
  2. API boundaries requiring explicit absence semantics.

Usually not useful:

  1. JPA entity fields and DTO internals,
  2. method arguments in most cases.

Common mistakes

  1. very long stream chains with dense business logic,
  2. side effects inside map/filter,
  3. Optional.get() without safety checks,
  4. using parallelStream() by default without benchmarks.

Practical workflow

  1. Define transformation steps first.
  2. Use streams for linear pipelines.
  3. Use loops for branch-heavy logic.
  4. Return Optional at boundaries for missing-value semantics.
  5. Keep readability above cleverness.

Key takeaway

Stream API improves composability and clarity of data transformations. Optional makes missing values explicit and safer.

Quiz

Check what you learned

Please login to pass quizzes.