Table of Contents


Terminal Optional methods

After chaining intermediate operations for filtering/transformation, terminal methods let you extract values, branch logic, and complete processing.

Extract value with get

get is the simplest way to extract wrapped value. But it requires care. If Optional is empty, NoSuchElementException is thrown.

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

So use get only when value presence is guaranteed.

// returns "str"
Optional.ofNullable("str").get();

// throws `NoSuchElementException`
Optional.ofNullable(null).get();

Set default with orElse

orElse sets default value for empty Optional. Method:

public T orElse(T other) {
    return value != null ? value : other;
}

If Optional has value, return it. Otherwise return provided default.

String str = null;

// returns "hi"
Optional.ofNullable(str).orElse("hi");

Set default with orElseGet

Similar to orElse, but orElseGet takes Supplier.

public T orElseGet(Supplier<? extends T> supplier) {
    return value != null ? value : supplier.get();
}
String str = null;

// returns "hi"
Optional.ofNullable(str).orElseGet(() -> "hi");

Difference between orElse and orElseGet

orElseGet can be seen as lazy version of orElse. orElseGet runs only when value is absent. orElse argument is always evaluated whether value exists or not.

User user = new User();

System.out.println("userByOrElse");
User orElse = Optional.ofNullable(user)
    .orElse(makeDefaultUser());

System.out.println("---------------");

System.out.println("userByOrElseGet");
User userByOrElseGet = Optional.ofNullable(user)
    .orElseGet(() -> makeDefaultUser());

Output:

userByOrElse
makeDefaultUser method called!
---------------
userByOrElseGet

As shown, orElse executes its argument even when Optional has value. So if argument method contains expensive or side-effect logic, take care.

For example, if it calls APIs or updates databases, using it in orElse can create unintended traffic or data mutation. Use orElseGet in such cases.

Throw exception with orElseThrow

Unlike orElse and orElseGet which provide defaults, orElseThrow throws exception when Optional is empty.

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

It is similar to get (which throws NoSuchElementException), but orElseThrow lets you choose exception type.

Optional.ofNullable(user)
    .orElseThrow(IllegalArgumentException::new);

// same as below
Optional.ofNullable(user)
    .orElseThrow(() -> {
        return new IllegalArgumentException();
    });

Java 10 added overloaded orElseThrow() without arguments. When no exception supplier is passed, default is NoSuchElementException.

public T orElseThrow() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

Conditional handling with ifPresent and ifPresentOrElse

ifPresent runs provided Consumer only when value exists. If empty, it does nothing.

public void ifPresent(Consumer<? super T> action) {
    if (value != null) {
        action.accept(value);
    }
}

Usage:

Optional.of("value").ifPresent(v -> {
    System.out.println(v); // runs
});

ifPresentOrElse was added in Java 9. Unlike ifPresent, it takes one more argument.

public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
    if (value != null) {
        action.accept(value);
    } else {
        emptyAction.run();
    }
}

First argument is Consumer for present value. Second is Runnable for empty case.

Optional.of("value").ifPresentOrElse(v -> {
    System.out.println(v); // runs
}, () -> {
	System.out.println("emitAction!"); // does not run
});

Optional.ofNullable(null).ifPresentOrElse(v -> {
    System.out.println(v); // does not run
}, () -> {
    System.out.println("emitAction!"); // runs
});

Check presence with isPresent and isEmpty

isPresent returns true when Optional has value, false otherwise.

public boolean isPresent() {
    return value != null;
}

isEmpty was added in Java 11 and does the opposite.

public boolean isEmpty() {
    return value == null;
}


Am I using it correctly?

So far, we covered Optional creation, filtering/transformation, and terminal operations for extraction and conditional handling.

Next is usage quality: applying Optional according to its design intent. The next post covers practical guidance for that.