Lab 03: Functional Interfaces & Optional

Objective

Master Java's built-in functional interfaces (Function, Predicate, BiFunction, Consumer, Supplier, UnaryOperator), compose them into pipelines, and use Optional for null-safe chaining.

Background

Functional interfaces are the backbone of Java lambdas — any interface with a single abstract method is a functional interface. The java.util.function package provides ~43 ready-made ones. Optional<T> replaces null-checks with expressive, chainable operations that make absent-value handling visible and safe.

Time

25 minutes

Prerequisites

  • Lab 02 (Streams & Lambdas)

Tools

  • Docker: zchencow/innozverse-java:latest


Lab Instructions

Step 1: Custom Functional Interfaces & Composition

💡 Optional.or() vs orElseGet(): Optional.or() returns a new Optional<T> (so you can keep chaining), while orElseGet() unwraps to a T. Use or() when you want to provide a fallback Optional, and orElseGet() when you want the actual value. Never use get() without isPresent() — it throws NoSuchElementException.

📸 Verified Output:


Summary

Interface
Signature
Use for

Function<T,R>

R apply(T t)

Transform T → R

BiFunction<T,U,R>

R apply(T,U)

Two-input transform

UnaryOperator<T>

T apply(T t)

Transform T → T

Predicate<T>

boolean test(T)

Filter condition

Consumer<T>

void accept(T)

Side-effect action

Supplier<T>

T get()

Lazy value factory

Comparator<T>

int compare(a,b)

Ordering

Further Reading

Last updated