Optional
By the Syncfusion DevTutorials team · Last updated
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:
- What
Optionalis. - Why
Optionalis used instead of returningnull. - How to create an
Optionalwithof,ofNullableandempty. - How to check for a value with
isPresent()andisEmpty(). - How to run code only when a value exists, with
ifPresent(). - How to give a fallback value with
orElse(). - How
orElseGet()differs fromorElse(), and when to use each.
Start With a Working Example
Press Run.
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:
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.
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.
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 anOptional<String>. You must take the value out first, so you think about the empty case. - Empty handling stays short. Methods like
orElsecan replace longerif (x != null)checks.
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:
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 | — |
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:
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.
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:
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.
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:
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.
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:
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 aSupplier: 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.
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:
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
Optionalis 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(nevernull),Optional.ofNullable(maybenull) orOptional.empty(). isPresent()andisEmpty()check the box. Only callget()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
Optionalfor return values, not for fields, parameters or collections.
Next: Pattern Matching