# Optional

Course: [Java](https://www.devtutorials.ai/learn/java) · Section: Modern Java Features
Source: https://www.devtutorials.ai/learn/java/modern-java-features/optional

> Handle missing values safely with Optional: create one with of, ofNullable and empty, then use isPresent, ifPresent, orElse and orElseGet.

Think about a parcel locker at a railway station.

You open locker 12. Sometimes there is a parcel inside. Sometimes the locker is empty. Either way, you get a locker. You never get "nothing at all".

Because you always get a locker, you know you must look inside before you take the parcel out.

Java's `Optional` is like that locker. A method that might not have an answer returns an `Optional`. It always gives you the box. The box either contains a value or is empty, so the code that receives it must check before using the value.

In simple words, an `Optional` is a box that holds one value or nothing. It helps you avoid surprises when a value is missing.

## What You Will Learn

In this lesson, you will learn:

1. What `Optional` is.
2. Why `Optional` is used instead of returning `null`.
3. How to create an `Optional` with `of`, `ofNullable` and `empty`.
4. How to check for a value with `isPresent()` and `isEmpty()`.
5. How to run code only when a value exists, with `ifPresent()`.
6. How to give a fallback value with `orElse()`.
7. How `orElseGet()` differs from `orElse()`, and when to use each.

## Start With a Working Example

Press **Run**.

```java runnable title="A search that might not find anything"
import java.util.List;
import java.util.Optional;

public class Main {
    static List<String> students = List.of("Asha", "Ravi", "Meena");

    public static void main(String[] args) {
        Optional<String> found = findStartingWith("R");
        Optional<String> missing = findStartingWith("Z");

        System.out.println("Starts with R: " + found.orElse("nobody"));
        System.out.println("Starts with Z: " + missing.orElse("nobody"));
    }

    static Optional<String> findStartingWith(String letter) {
        for (String s : students) {
            if (s.startsWith(letter)) {
                return Optional.of(s);
            }
        }
        return Optional.empty();
    }
}
```

Expected output:

```text
Starts with R: Ravi
Starts with Z: nobody
```

The method always returns an `Optional`. For `"R"`, the box holds `Ravi`. For `"Z"`, the box is empty.

`orElse("nobody")` takes the value out of the box, or uses `"nobody"` when the box is empty. The program does not have to deal with `null`.

### Try This

Change `"Z"` to `"M"`. The second line now prints `Meena`, because the box is no longer empty.

## What is Optional?

**`Optional<T>`** is a class in `java.util`. An `Optional` object is a **container** that holds either:

- **one value** of type `T`, or
- **nothing**. This is called an **empty** `Optional`.

The type in angle brackets says what the box can hold. `Optional<String>` might hold a `String`. `Optional<Integer>` might hold an `Integer`.

`Optional` was added in Java 8. You already met it in the Streams lesson: `findFirst()` returns an `Optional`, because a stream might have no elements.

```text
 Optional.of("Ravi")           Optional.empty()
 ┌──────────────┐              ┌──────────────┐
 │   "Ravi"     │              │              │
 └──────────────┘              └──────────────┘
   present                       empty
```

`Optional` is mainly meant as a **return type**. It is a way for a method to say, "I might not have an answer for you".

## Why Optional Is Used

Before `Optional`, a method with no answer usually returned `null`.

The problem with `null` is that it looks like a normal value in the method signature. Nothing reminds the caller to check for it. If they forget, the program crashes with a **`NullPointerException`**, often far away from where the `null` came from.

```text
String email = findEmail("Arjun");   // returns null: Arjun has no email
email.toUpperCase();                  // NullPointerException
```

`Optional` helps in three ways:

- **The return type tells the truth.** `Optional<String>` clearly says, "this might be empty".
- **The compiler helps.** You cannot call `toUpperCase()` directly on an `Optional<String>`. You must take the value out first, so you think about the empty case.
- **Empty handling stays short.** Methods like `orElse` can replace longer `if (x != null)` checks.

```java runnable title="null forces a check you can forget, Optional makes it obvious"
import java.util.Map;
import java.util.Optional;

public class Main {
    static Map<String, String> emails = Map.of("Asha", "asha@mail.com", "Ravi", "ravi@mail.com");

    public static void main(String[] args) {
        String oldWay = findEmailOrNull("Arjun");
        if (oldWay != null) {
            System.out.println("Old way: " + oldWay.toUpperCase());
        } else {
            System.out.println("Old way: no email");
        }

        String newWay = findEmail("Arjun")
                .map(String::toUpperCase)
                .orElse("no email");
        System.out.println("New way: " + newWay);

        System.out.println("Asha: " + findEmail("Asha").orElse("no email"));
    }

    static String findEmailOrNull(String name) {
        return emails.get(name);
    }

    static Optional<String> findEmail(String name) {
        return Optional.ofNullable(emails.get(name));
    }
}
```

Expected output:

```text
Old way: no email
New way: no email
Asha: asha@mail.com
```

The old way needs an `if` check. Forgetting it would crash the program.

The new way reads as one sentence: find the email, turn it into capitals, or else say "no email". `map` only runs when there is a value, just like `map` on a stream.

`Optional` is designed for **return values**. Do not use it for fields, method parameters or collections. A list that might have no items should simply be an empty list, not an `Optional<List<...>>`.

## Creating Optionals

There are three ways to create an `Optional`.

| Method | Use when | If the value is `null` |
|---|---|---|
| `Optional.of(value)` | You are **sure** the value is not `null` | Throws `NullPointerException` |
| `Optional.ofNullable(value)` | The value **might** be `null` | Returns an empty `Optional` |
| `Optional.empty()` | You want an empty box on purpose | — |

```java runnable title="of, ofNullable and empty"
import java.util.Optional;

public class Main {
    public static void main(String[] args) {
        Optional<String> city = Optional.of("Chennai");
        Optional<String> maybeCity = Optional.ofNullable(null);
        Optional<String> nothing = Optional.empty();

        System.out.println("of: " + city);
        System.out.println("ofNullable(null): " + maybeCity);
        System.out.println("empty: " + nothing);

        String fromDatabase = null;
        Optional<String> safe = Optional.ofNullable(fromDatabase);
        System.out.println("Safe box is empty? " + safe.isEmpty());
    }
}
```

Expected output:

```text
of: Optional[Chennai]
ofNullable(null): Optional.empty
empty: Optional.empty
Safe box is empty? true
```

When printed, a full box shows `Optional[value]`, and an empty box shows `Optional.empty`.

`ofNullable` is the safe choice when the value comes from somewhere you do not control, like a map lookup or a database.

`Optional.of(null)` throws a `NullPointerException` straight away. Use `Optional.of` only when you are certain the value exists. When in doubt, use `Optional.ofNullable`.

## isPresent()

`isPresent()` returns `true` if the box holds a value, and `false` if it is empty.

`isEmpty()` (added in Java 11) does the opposite: it returns `true` if the box is empty.

You can then take the value out with `get()`. But `get()` on an empty box throws a `NoSuchElementException`, so only call it after checking.

```java runnable title="Check first, then take the value out"
import java.util.Optional;

public class Main {
    public static void main(String[] args) {
        Optional<Integer> marks = Optional.of(87);
        Optional<Integer> absent = Optional.empty();

        System.out.println("marks present? " + marks.isPresent());
        System.out.println("absent present? " + absent.isPresent());
        System.out.println("absent empty? " + absent.isEmpty());

        if (marks.isPresent()) {
            int m = marks.get();
            System.out.println("Marks plus bonus: " + (m + 5));
        }

        if (absent.isPresent()) {
            System.out.println("This line never prints");
        } else {
            System.out.println("No marks recorded");
        }
    }
}
```

Expected output:

```text
marks present? true
absent present? false
absent empty? true
Marks plus bonus: 92
No marks recorded
```

This works, but it looks a lot like the old `if (x != null)` style. The methods in the rest of this lesson are usually shorter and safer.

## ifPresent()

`ifPresent(action)` runs an action **only when** the box holds a value. If the box is empty, nothing happens.

The action is a `Consumer`, usually written as a lambda.

`ifPresentOrElse(action, emptyAction)` (added in Java 9) also lets you say what to do when the box is empty.

```java runnable title="Run code only when there is a value"
import java.util.Optional;

public class Main {
    public static void main(String[] args) {
        Optional<String> coupon = Optional.of("SAVE20");
        Optional<String> noCoupon = Optional.empty();

        coupon.ifPresent(c -> System.out.println("Applying coupon " + c));
        noCoupon.ifPresent(c -> System.out.println("This never prints"));

        noCoupon.ifPresentOrElse(
                c -> System.out.println("Applying coupon " + c),
                () -> System.out.println("No coupon, full price"));
    }
}
```

Expected output:

```text
Applying coupon SAVE20
No coupon, full price
```

`noCoupon.ifPresent(...)` printed nothing at all, because the box was empty.

Use `ifPresent` when there is something to **do** with the value. Use `orElse` when you need to **get** a value back.

## orElse()

`orElse(fallback)` returns the value in the box, or the `fallback` if the box is empty.

It always gives you a real value, so you can use the result straight away.

```java runnable title="orElse always gives you something to use"
import java.util.Map;
import java.util.Optional;

public class Main {
    static Map<String, Integer> stock = Map.of("Pens", 40, "Bags", 6);

    public static void main(String[] args) {
        int pens = Optional.ofNullable(stock.get("Pens")).orElse(0);
        int shoes = Optional.ofNullable(stock.get("Shoes")).orElse(0);

        System.out.println("Pens in stock: " + pens);
        System.out.println("Shoes in stock: " + shoes);

        String nickname = Optional.<String>empty().orElse("Guest");
        System.out.println("Hello, " + nickname);
    }
}
```

Expected output:

```text
Pens in stock: 40
Shoes in stock: 0
Hello, Guest
```

Shoes are not in the map, so the box was empty, and `orElse(0)` gave `0`.

`Optional.<String>empty()` tells Java the box would hold a `String`, so `orElse("Guest")` fits.

## orElseGet()

`orElseGet(supplier)` also returns the value, or a fallback when the box is empty. The difference is **how** the fallback is made.

- `orElse(fallback)` takes a **ready-made value**. That value is worked out **every time**, even if the box is full and it is not needed.
- `orElseGet(supplier)` takes a **`Supplier`**: a lambda that makes the value. The lambda only runs **when the box is empty**.

This matters when the fallback is **expensive** to make, such as reading a file or calling a database.

```java runnable title="orElse always builds the fallback, orElseGet only when needed"
import java.util.Optional;

public class Main {
    public static void main(String[] args) {
        Optional<String> saved = Optional.of("Dark theme");

        System.out.println("Using orElse:");
        String a = saved.orElse(loadDefaultTheme());
        System.out.println("  Result: " + a);

        System.out.println("Using orElseGet:");
        String b = saved.orElseGet(() -> loadDefaultTheme());
        System.out.println("  Result: " + b);

        System.out.println("orElseGet on an empty box:");
        String c = Optional.<String>empty().orElseGet(Main::loadDefaultTheme);
        System.out.println("  Result: " + c);
    }

    static String loadDefaultTheme() {
        System.out.println("  (loading the default theme from disk...)");
        return "Light theme";
    }
}
```

Expected output:

```text
Using orElse:
  (loading the default theme from disk...)
  Result: Dark theme
Using orElseGet:
  Result: Dark theme
orElseGet on an empty box:
  (loading the default theme from disk...)
  Result: Light theme
```

With `orElse`, Java ran `loadDefaultTheme()` even though the box already held "Dark theme". The work was wasted.

With `orElseGet`, the lambda was skipped because the box was full. It only ran for the empty box.

| | `orElse(value)` | `orElseGet(supplier)` |
|---|---|---|
| Takes | A ready value | A lambda that makes a value |
| Fallback is worked out | Always | Only when the box is empty |
| Best for | Simple, cheap values like `0`, `""` or `"Guest"` | Expensive work, like reading a file or a database |
| Example | `opt.orElse("Guest")` | `opt.orElseGet(() -> loadFromDb())` |

**Easy Way to Remember:** `orElse` for a **constant**, `orElseGet` for a **calculation**.

### More Ways to Handle an Empty Box

| Method | What it does |
|---|---|
| `orElseThrow()` | Returns the value, or throws `NoSuchElementException` |
| `orElseThrow(() -> new X(...))` | Returns the value, or throws your own exception |
| `map(fn)` | Changes the value, if there is one |
| `filter(rule)` | Keeps the value only if it passes the rule |

## Common mistakes

The following mistakes are common when using `Optional`. Each row shows what you see, why it happens and how to fix it.

| Symptom | Cause | Fix |
|---|---|---|
| `NoSuchElementException: No value present` | `get()` on an empty `Optional` | Use `orElse`, `orElseGet` or `ifPresent` |
| `NullPointerException` when creating an `Optional` | `Optional.of(null)` | Use `Optional.ofNullable` |
| `NullPointerException` from an `Optional` variable | A method returned `null` instead of an `Optional` | Return `Optional.empty()` |
| A slow program, even when values exist | Expensive work passed to `orElse` | Use `orElseGet` with a lambda |
| Code full of `isPresent()` / `get()` pairs | Treating `Optional` like a `null` check | Use `ifPresent`, `map` and `orElse` |

## What to Remember

- An `Optional` is a box that holds one value or nothing.
- It makes "there might be no answer" clear in a method's return type, and helps avoid `NullPointerException`.
- Create one with `Optional.of` (never `null`), `Optional.ofNullable` (maybe `null`) or `Optional.empty()`.
- `isPresent()` and `isEmpty()` check the box. Only call `get()` after checking, or better, avoid it.
- `ifPresent()` runs code only when there is a value.
- `orElse()` gives a fallback that is always worked out. `orElseGet()` builds the fallback only when the box is empty.
- Use `Optional` for return values, not for fields, parameters or collections.

Next: Pattern Matching
