Optional — Null Safety
Optional — NullPointerException থেকে বাঁচার type-safe উপায়
1. The Billion-Dollar Mistake
null is the default absence marker in Java — and the source of countless
NullPointerExceptions in production. Tony Hoare, who introduced it in 1965, calls it his
"billion-dollar mistake." Java 8 introduced Optional<T>, a container
that either holds a value or is empty, making absence visible in the type system.
null — default "কিছু নেই" signal — production-এ অসংখ্য NullPointerException-এর উৎস। Tony Hoare ১৯৬৫ সালে null-কে তাঁর "billion-dollar mistake" বলেছিলেন। Java 8 দিয়েছে Optional<T> — একটি container যা হয় value রাখে নয়তো empty; এটি type-system-এ "absence" দৃশ্যমান করে।
2. Creating an Optional
Use Optional.of(x) for a known-non-null value, Optional.empty() for nothing,
and Optional.ofNullable(x) when x may itself be null.
Optional.of(x) — non-null value; Optional.empty() — কিছু নেই; Optional.ofNullable(x) — x নিজেই null হতে পারে এমন ক্ষেত্রে।
import java.util.*;
class Main {
public static void main(String[] args) {
Optional<String> a = Optional.of("ABCL TECH");
Optional<String> b = Optional.empty();
String nullable = System.getenv("DOES_NOT_EXIST"); // returns null
Optional<String> c = Optional.ofNullable(nullable);
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
}
}
Optional.of(null) throws NullPointerException immediately.
If the value might be null, always use ofNullable.
Optional.of(null) সরাসরি NullPointerException ছুড়ে দেয় — null হতে পারে এমন value-তে সব সময় ofNullable।
3. Consuming an Optional
Prefer ifPresent, orElse, orElseGet, and orElseThrow.
Avoid .get() without an isPresent check — that's basically null with
extra steps.
ifPresent, orElse, orElseGet, orElseThrow ব্যবহার করুন। isPresent check ছাড়া .get() এড়িয়ে চলুন — সেটি আসলে null-ই, শুধু একটু ঘুরিয়ে।
import java.util.*;
class Main {
static Optional<String> findUser(int id) {
return id == 1 ? Optional.of("Arif") : Optional.empty();
}
public static void main(String[] args) {
findUser(1).ifPresent(n -> System.out.println("found: " + n));
findUser(2).ifPresent(n -> System.out.println("never runs"));
String fallback = findUser(2).orElse("(anonymous)");
System.out.println("fallback = " + fallback);
// orElseGet: compute default lazily
String lazyFallback = findUser(2).orElseGet(() -> "computed-default");
System.out.println("lazy = " + lazyFallback);
// orElseThrow
try {
findUser(2).orElseThrow(() -> new RuntimeException("not found"));
} catch (RuntimeException ex) {
System.out.println("caught: " + ex.getMessage());
}
}
}
4. map & flatMap on Optional
Just like streams, Optional has map (transform the inner value if present) and
flatMap (when the transformation itself returns an Optional). Chaining these avoids
nested if (x != null).
map (ভেতরের value transform) ও flatMap (যখন transform নিজেই Optional দেয়) আছে। Chain করলে nested if (x != null) লাগে না।
import java.util.*;
class Main {
record Address(String city) {}
record User(String name, Optional<Address> addr) {}
public static void main(String[] args) {
User u1 = new User("Arif", Optional.of(new Address("Dhaka")));
User u2 = new User("Rina", Optional.empty());
// Without Optional, this would be 4 nested null checks
String c1 = u1.addr().map(Address::city).orElse("?");
String c2 = u2.addr().map(Address::city).orElse("?");
System.out.println("u1 city = " + c1);
System.out.println("u2 city = " + c2);
// flatMap — when the mapping itself returns Optional
Optional<String> shout = Optional.of("abcl")
.flatMap(s -> Optional.of(s.toUpperCase()));
System.out.println("shout = " + shout);
}
}
5. Anti-Patterns to Avoid
⚠️ Don't Do This
opt.get()withoutisPresent- Taking
Optionalas a method parameter - Storing
Optionalin a field or collection Optional.of(x)whenxmay be nullopt.orElse(expensiveCall())— eager
✅ Do This Instead
opt.ifPresent(...)/orElse(...)/orElseThrow(...)- Use plain parameter; let null-handling stay at the call site
- Use a sentinel value or a primitive; keep Optional for return types
Optional.ofNullable(x)opt.orElseGet(() -> expensiveCall())
get()-এর বদলে ifPresent/orElse; expensive default হলে orElseGet।
6. Vocabulary
| Method | Meaning | বাংলায় |
|---|---|---|
Optional.of(x) | Non-null value; throws NPE if x is null. | Non-null value; null হলে NPE। |
Optional.ofNullable(x) | Empty if x is null, else present. | x null হলে empty। |
isPresent / isEmpty | Check presence/absence. | Presence/absence check। |
ifPresent(c) | Run consumer if value present. | Value থাকলে consumer চালায়। |
orElse(def) | Eager default. | Default value (eager)। |
orElseGet(sup) | Lazy default (Supplier). | Lazy default। |
orElseThrow(sup) | Throw on empty. | Empty হলে exception। |
map / flatMap | Transform inside; flat avoids nested Optional. | ভেতরে transform; flatMap nested Optional এড়ায়। |
7. Practice Problems
-
Return an
Optional<String>that is empty when input is null, else contains the trimmed string.input null হলে empty, নয়তো trimmed string-বিশিষ্টOptional<String>ফেরত দিন।✨ Show Answer
Main.javaimport java.util.*; class Main { static Optional<String> cleaned(String s) { return Optional.ofNullable(s).map(String::trim); } public static void main(String[] args) { System.out.println(cleaned(" hi ")); System.out.println(cleaned(null)); } } -
Given an
Optional<Integer>, print double the value if present, else "no value".Optional<Integer>-এ value থাকলে দ্বিগুণ প্রিন্ট করুন, নয়তো "no value"।✨ Show Answer
Main.javaimport java.util.*; class Main { public static void main(String[] args) { Optional<Integer> x = Optional.of(7); System.out.println(x.map(n -> n * 2).map(String::valueOf).orElse("no value")); Optional<Integer> y = Optional.empty(); System.out.println(y.map(n -> n * 2).map(String::valueOf).orElse("no value")); } } -
Why is
orElseGetpreferable toorElsefor expensive defaults?Expensive default-এর জন্যorElse-এর বদলেorElseGetকেন ভালো?✨ Show Answer
Answer:
orElse(x)evaluatesxeagerly — before checking whether the Optional is present — so any expensive computation runs even when the value was present and the default isn't needed.orElseGet(Supplier)evaluates the supplier only when the Optional is empty. For expensive defaults (a database call, heavy object construction), always preferorElseGet.orElse(x)x-কে আগেই evaluate করে — Optional-এ value থাকলেও expensive computation চলে যায়।orElseGet(Supplier)শুধু empty হলেই supplier চালায়। DB call-এর মতো ভারী default-এর জন্য সব সময়orElseGet। -
Use
flatMapto get the first letter of a user's city (with nullable address).flatMapদিয়ে user-এর city-র প্রথম অক্ষর বের করুন (address null-হতে পারে)।✨ Show Answer
Main.javaimport java.util.*; class Main { record Addr(String city) {} record User(String name, Optional<Addr> addr) {} public static void main(String[] args) { User u = new User("Arif", Optional.of(new Addr("Dhaka"))); char c = u.addr().map(Addr::city).map(s -> s.charAt(0)).orElse('?'); System.out.println(c); } } -
Why should we not accept
Optional<T>as a method parameter?Optional<T>-কে method parameter হিসেবে কেন গ্রহণ করা উচিত নয়?✨ Show Answer
Answer: Because the caller must build an
Optionaljust to pass it — and then could still passnull, giving you three states to handle (null, empty, present) instead of two. Accept a plain value; overload the method, or use two methods, if some call sites have nothing to pass. The Java community's consensus: useOptionalonly as a return type.কারণ caller-কে Optional বানিয়ে pass করতে হবে — এবং তারপরও
null-ও pass করতে পারে, ফলে তিনটি state সামলাতে হবে (null, empty, present)। প্লেইন value নিন; দরকার হলে method overload করুন। Java community-র convention:Optional-কে শুধু return type হিসেবে ব্যবহার করা।
Summary — Module 30
Optional<T> is Java's type-safe way to say "maybe a value." Use it primarily as a
return type. Create with ofNullable, consume with ifPresent,
orElseGet, or orElseThrow. Chain with map and flatMap
to avoid nested null checks. Never use Optional as a method parameter, field, or collection
element.
Optional<T> হলো type-safe "হয়তো একটি value"। মূলত return type হিসেবেই ব্যবহার করুন। ofNullable দিয়ে বানান, ifPresent/orElseGet/orElseThrow-দিয়ে consume করুন, map/flatMap-এ chain করুন। Parameter/field/collection-এ Optional রাখবেন না।