Java + Spring Boot track

Lesson 19 · Part 5: Modern Java

Optional

Optional is a container that specifies "may or may not have a value" as type. When used in methods where the return value can be null, it forces the caller to never…

Part 5: Modern Java3 min readFree lesson

Optional<T> is a container that specifies "may or may not have a value" as type. When used in methods where the return value can be null, it forces the caller to never forget to check for null, reducing NPEs.

Learning Objectives

  • Use Optional.of / ofNullable / empty
  • Know map / filter / orElse / orElseThrow / ifPresent
  • Learn the pattern of using Optional as return type
  • Do not use Optional in antipatterns (fields, parameters, collection elements)

Key concepts

1) Create

Optional<String> a = Optional.of("hi");          //If null, NPE
Optional<String> b = Optional.ofNullable(maybe); //nullable
Optional<String> c = Optional.empty();

2) Retrieve value

String v = a.orElse("default");
String w = a.orElseThrow(() -> new IllegalStateException("None"));
a.ifPresent(System.out::println);

get() is not recommended because it throws an exception when the value is missing.

3) Transformation and filter

Optional<Integer> len = a.map(String::length);
Optional<String> upper = a.filter(s -> s.length() > 3).map(String::toUpperCase);

4) Anti-pattern

  • Use of Optional as a field type
  • Use Optional as parameter type
  • Use Optional as collection element type

See as example

Example 1 — OptionalBasics.java: Create/Remove

import java.util.Optional;

public class OptionalBasics {
    public static void main(String[] args) {
        Optional<String> hi = Optional.of("hi");
        Optional<String> empty = Optional.empty();

        System.out.println(hi.isPresent());
        System.out.println(empty.isPresent());

        System.out.println(hi.orElse("default"));
        System.out.println(empty.orElse("default"));

        hi.ifPresent(s -> System.out.println("value=" + s));
        empty.ifPresent(s -> System.out.println("Not running"));
    }
}

Execution result

true
false
hi
default
value=hi

Note: ifPresent only executes lambda when there is a value.

Example 2 — OptionalMapFilter.java: Transformation/Filter Chaining

import java.util.Optional;

public class OptionalMapFilter {
    public static void main(String[] args) {
        Optional<String> name = Optional.of("Java");
        Optional<Integer> len = name.map(String::length);
        len.ifPresent(n -> System.out.println("length=" + n));

        Optional<String> longName = Optional.of("hi")
            .filter(s -> s.length() > 3)
            .map(String::toUpperCase);
        System.out.println("Long name?" + longName);
    }
}

Execution result

length=4
Long name? Optional.empty

Memo: If filter is false, an empty Optional flows to the end of the chain.

Example 3 — OptionalReturn.java: used as return type

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class OptionalReturn {
    static Map<String, Integer> ages = Map.of("exponent", 21, "Minsu", 25);

    static Optional<Integer> findAge(String name) {
        return Optional.ofNullable(ages.get(name));
    }

    public static void main(String[] args) {
        System.out.println(findAge("exponent").orElse(-1));
        System.out.println(findAge("unknown").orElse(-1));

        findAge("Minsu").ifPresent(a -> System.out.println("Minsu=" + a));
    }
}

Execution result

21
-1
Minsu=25

Memo: If Optional is used in the method return type, the caller will consciously handle null.

Example 4 — OrElseThrow.java: Exception when not present

import java.util.Optional;

public class OrElseThrow {
    public static void main(String[] args) {
        Optional<String> ok = Optional.of("value");
        Optional<String> none = Optional.empty();

        System.out.println(ok.orElseThrow());

        try {
            none.orElseThrow(() -> new IllegalStateException("Missing required value"));
        } catch (IllegalStateException e) {
            System.out.println("Exception:" + e.getMessage());
        }
    }
}

Execution result

value
Exception: Required value missing

Note: orElseThrow is often used with exceptions where the domain meaning is clear.

Common Mistakes

  1. Optional.of(null) → Immediate NPE. If there is a null possibility, ofNullable
  2. Uncritical use of get()
  3. Field type Optional (conflicts with Serialization/JPA)
  4. Empty list List<X> is more natural than Optional<List<X>>
  5. If you write Optional as if-else, its meaning disappears — Use of map/orElse chaining

Cleanup

  • Optional is best suited as return type
  • orElse/orElseThrow/ifPresent is safer than get()
  • Remove if overlap with map/filter chaining

Try it yourself

cd 05_Modern_Java/19_Optional/src
javac OptionalReturn.java
java OptionalReturn

Example files

The runnable files used in this lesson. Copy them into your own project and experiment.

src/OptionalBasics.javaJava
import java.util.Optional;

public class OptionalBasics {
    public static void main(String[] args) {
        Optional<String> hi = Optional.of("hi");
        Optional<String> empty = Optional.empty();

        System.out.println(hi.isPresent());
        System.out.println(empty.isPresent());

        System.out.println(hi.orElse("default"));
        System.out.println(empty.orElse("default"));

        hi.ifPresent(s -> System.out.println("value=" + s));
        empty.ifPresent(s -> System.out.println("Not running"));
    }
}
src/OptionalMapFilter.javaJava
import java.util.Optional;

public class OptionalMapFilter {
    public static void main(String[] args) {
        Optional<String> name = Optional.of("Java");
        Optional<Integer> len = name.map(String::length);
        len.ifPresent(n -> System.out.println("length=" + n));

        Optional<String> longName = Optional.of("hi")
            .filter(s -> s.length() > 3)
            .map(String::toUpperCase);
        System.out.println("Long name?" + longName);
    }
}
src/OptionalReturn.javaJava
import java.util.Map;
import java.util.Optional;

public class OptionalReturn {
    static Map<String, Integer> ages = Map.of("exponent", 21, "Minsu", 25);

    static Optional<Integer> findAge(String name) {
        return Optional.ofNullable(ages.get(name));
    }

    public static void main(String[] args) {
        System.out.println(findAge("exponent").orElse(-1));
        System.out.println(findAge("unknown").orElse(-1));

        findAge("Minsu").ifPresent(a -> System.out.println("Minsu=" + a));
    }
}
src/OrElseThrow.javaJava
import java.util.Optional;

public class OrElseThrow {
    public static void main(String[] args) {
        Optional<String> ok = Optional.of("value");
        Optional<String> none = Optional.empty();

        System.out.println(ok.orElseThrow());

        try {
            none.orElseThrow(() -> new IllegalStateException("Missing required value"));
        } catch (IllegalStateException e) {
            System.out.println("Exception:" + e.getMessage());
        }
    }
}

Assignment

Problem 1 — User Lookup

  • File name: Homework01.java
  • Key concepts: Return Optional, orElse, ifPresent

Requirements

  • Create a Optional<String> findEmail(String userId) method and search in the internal Map ([email protected], [email protected]).
  • Search as id1, id3 and output in the following format.

Expected output

id1 -> [email protected]
id3 -> None

Problem 2 — Safe Average

  • File name: Homework02.java
  • Core concepts: OptionalDouble, IntStream.average

Requirements

  • static OptionalDouble safeAvg(int[] arr) — empty if it is an empty array.
  • Handled two cases, [1,2,3,4] and [].

Expected output

average=2.5
no average

Check the correct answer

After solving it yourself, compare it with the reference solution below.

Show the reference solution

Try the assignment yourself first — comparing your attempt with a working solution is where most of the learning happens.

Homework01.javaJava
import java.util.Map;
import java.util.Optional;

/** User email inquiry with Optional.*/
public class Homework01 {
    static Map<String, String> emails = Map.of("id1", "[email protected]", "id2", "[email protected]");

    public static void main(String[] args) {
        for (String id : new String[]{"id1", "id3"}) {
            String email = findEmail(id).orElse("None");
            System.out.println(id + " -> " + email);
        }
    }

    static Optional<String> findEmail(String userId) {
        return Optional.ofNullable(emails.get(userId));
    }
}
Homework02.javaJava
import java.util.OptionalDouble;
import java.util.stream.IntStream;

/** Safe average.*/
public class Homework02 {
    public static void main(String[] args) {
        for (int[] arr : new int[][]{ {1, 2, 3, 4}, {} }) {
            OptionalDouble avg = safeAvg(arr);
            if (avg.isPresent()) {
                System.out.println("average=" + avg.getAsDouble());
            } else {
                System.out.println("no average");
            }
        }
    }

    static OptionalDouble safeAvg(int[] arr) {
        return IntStream.of(arr).average();
    }
}

Learn this lesson with a mentor

Work through the Java + Spring Boot track on your own, or join a guided cohort at our Pitampura campus and online.

Call NowEnroll Now