Skip to content

Lesson 04 · Optional & Primitive Streams

Objectives

After this lesson you will be able to:

  • Use Optional correctly (map, filter, orElse, orElseGet, orElseThrow).
  • Use the primitive streams IntStream/LongStream/DoubleStream.
  • Get summary statistics and convert between object and primitive streams.

Optional

Optional<T> models "a value or nothing" without null. Build it, transform it, then extract a value with a fallback.

java
Optional<String> o = Optional.of("hi");        // of(null) throws NPE
Optional<String> e = Optional.empty();
Optional<String> n = Optional.ofNullable(maybeNull);

o.map(String::length).filter(len -> len > 1);  // chainable, stays Optional
o.orElse("default");                            // fallback value
o.orElseGet(() -> compute());                   // fallback supplier (lazy)
o.orElseThrow();                                // NoSuchElementException if empty
o.ifPresent(System.out::println);

Exam trap

Optional.get() on an empty Optional throws NoSuchElementException — prefer orElseThrow/ orElse. orElse(x) always evaluates x, even when the value is present; orElseGet(supplier) runs the supplier only when empty (use it when the fallback is expensive). Optional.of(null) throws NPE — use ofNullable.

Primitive streams

IntStream, LongStream, and DoubleStream avoid boxing and add numeric operations (sum, average, max, range).

java
int sum = IntStream.rangeClosed(1, 5).sum();           // 15 (1..5 inclusive)
OptionalDouble avg = IntStream.of(1, 2, 3).average();  // OptionalDouble[2.0]
int[] arr = IntStream.range(0, 3).toArray();           // {0,1,2}

Gotcha

range(a, b) is end-exclusive; rangeClosed(a, b) includes b. sum() on an IntStream returns an int (can overflow), but average()/max() return OptionalDouble/OptionalInt because the stream may be empty.

Converting between stream kinds

java
List<String> names = ...;
int totalLen = names.stream().mapToInt(String::length).sum();   // Stream<String> → IntStream
IntSummaryStatistics stats = names.stream().mapToInt(String::length).summaryStatistics();
stats.getMax(); stats.getAverage(); stats.getCount();

Stream<Integer> boxed = IntStream.range(0, 3).boxed();          // IntStream → Stream<Integer>

SDET note

summaryStatistics() gives count, sum, min, max, and average in one pass — handy for asserting aggregate properties of generated test data without writing several loops.

Key Takeaways

  • Optional replaces null: build with of/ofNullable/empty; transform with map/filter; extract with orElse/orElseGet/orElseThrow. get() on empty throws.
  • orElse is eager, orElseGet is lazy — matters when the fallback is costly.
  • Primitive streams (IntStream/…) avoid boxing and add sum/average/range/rangeClosed (range is exclusive, rangeClosed inclusive).
  • Convert with mapToInt/boxed; summaryStatistics() yields count/sum/min/max/avg in one pass.

Lesson Quiz

Lesson Quiz · Optional & Primitive Streams0 / 5
  1. What does Optional.empty().get() do?

    • AReturns null
    • BReturns Optional.empty
    • CNoSuchElementException
    • DCompile error
  2. Difference between orElse and orElseGet?

    • ANone
    • BorElse always evaluates its argument; orElseGet runs the supplier only when empty
    • CorElseGet is eager
    • DorElse takes a supplier
  3. What is IntStream.range(1, 5).sum()?

    • A15
    • B10
    • C1+2+3+4 = 10
    • DBoth B and C
  4. Why does IntStream.of(1,2,3).average() return OptionalDouble?

    • AIt's always present
    • BThe stream could be empty
    • CAverages are doubles
    • DTo avoid overflow
  5. What does Optional.of(null) do?

    • AOptional.empty
    • BOptional[null]
    • CNullPointerException
    • DCompile error

Next: Module 06 Mini-Exam. Run the matching code in labs/src/main/java/com/jse21/m06_streams/.