Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

Optional in Practice: Null-Safety without Drama

Posted on June 6, 2015October 17, 2025 By Luis Fernandez

Why are we still tripping on null?

Null pointer is still the top crash in production logs. We have better servers, fancier build tools, and yet a tiny ghost sneaks in and flips the table.

Java 8 gave us Optional. Not as a silver bullet. As a seatbelt. The point is not to remove every null. The point is to make absence explicit where it matters.

So how do you use Optional without drama?

What problem are we solving?

When a value might be missing, we want the signature to speak up. Optional makes absence visible. That is it. No magic.

Think find by id, maybe a config flag, maybe a header in a request. You can still return null, but Optional forces a small pause at the call site. That pause saves bugs.

Where should Optional appear?

Short rule for Java 8 Optional best practices: return Optional from queries that may not find a single value. Keep it out of fields and keep it out of method parameters.

In a repository or service:

interface UserRepository {
    Optional<User> findByEmail(String email);
}

userRepository.findByEmail(email)
    .ifPresent(this::sendWelcome);

Should I accept Optional as a parameter?

No. Parameters should be concrete. If a parameter is optional, offer an overload, a builder, or separate methods. Passing Optional into a method pushes decision making to callers and that spreads confusion.

// Bad
void schedule(Optional<Instant> runAt);

// Better
void schedule();
void scheduleAt(Instant runAt);

What about fields and JSON or JPA?

Keep Optional out of fields. Many tools still do not understand it. JPA does not map it. Jackson is still learning. Put null in the field and wrap on the getter.

class User {
    private Address address; // can be null

    public Optional<Address> address() {
        return Optional.ofNullable(address);
    }
}

This keeps frameworks calm and gives readers a clear signal at the edge of your class.

How do I chain without nested ifs?

Use map, flatMap, filter, and ifPresent. The goal is to express intent with little ceremony.

Optional.ofNullable(request)
    .map(Request::getUser)
    .map(User::getEmail)
    .filter(this::looksValidEmail)
    .ifPresent(emailService::sendReceipt);

That reads like a tiny pipeline. No null checks, no nesting.

When do I throw?

When absence is exceptional, throw at the edge. orElseThrow is perfect here.

User user = userRepository.findById(id)
    .orElseThrow(() -> new NotFound("user " + id));

Callers read it and know the contract. No surprise null pointer later.

orElse or orElseGet?

orElse always evaluates its argument. orElseGet runs only if empty. If the default is cheap, use orElse. If it calls a service or builds a heavy object, use orElseGet.

// Eager
String name = optName.orElse(expensiveLookup());

// Lazy
String name = optName.orElseGet(() -> expensiveLookup());

Can I put Optional in a Stream?

Yes, and it reads well if you unwrap early. In Java 8 we do a tiny helper. From Java 9 we get Optional.stream, but not today.

static <T> Stream<T> present(Stream<Optional<T>> stream) {
    return stream.filter(Optional::isPresent)
                 .map(Optional::get);
}

// Usage
Stream<Order> orders = present(customers.map(c -> repo.lastOrderOf(c)));

Optional or empty collections?

Return an empty List or Set instead of Optional of List. A collection already speaks about emptiness. Two layers of absence do not add clarity.

// Prefer
List<Order> findOrders(User u) { return Collections.emptyList(); }

// Avoid
Optional<List<Order>> findOrders(User u)

How do I migrate a large codebase?

Pick the edges. Start with repository returns. Then service lookups. Then configuration reads. Wrap nulls close to the source and let Optional travel outward.

// Step 1: wrap at the boundary
Optional<Config> cfg = Optional.ofNullable(env.get("feature.cfg"));

// Step 2: teach callers
String mode = cfg.map(Config::mode).orElse("safe");

Do not try to convert everything in one sprint. Small wins stick.

What about Guava Optional?

Many teams use Guava today. You can bridge with tiny helpers and phase it out over time.

static <T> Optional<T> j8(com.google.common.base.Optional<T> g) {
    return g.isPresent() ? Optional.of(g.get()) : Optional.empty();
}

static <T> com.google.common.base.Optional<T> guava(Optional<T> j) {
    return j.isPresent() ? com.google.common.base.Optional.of(j.get())
                         : com.google.common.base.Optional.absent();
}

New code on Java Optional. Adapters where the seam meets older code.

And Android or older JDKs?

Android is not on Java 8 today. Many apps use Retrolambda for lambdas and Guava for Optional. If that is your world, stay with Guava Optional on device code and use Java Optional on server code.

The idea is the same. Presence or absence made obvious.

What are the common bad patterns?

Calling isPresent then get. That is just a noisy null check. Prefer map or orElseThrow. Also do not store Optionals in fields or send them over the wire.

// Bad
if (userOpt.isPresent()) {
    userService.notify(userOpt.get());
}

// Better
userOpt.ifPresent(userService::notify);

How do we keep the team on the same page?

Add a short checklist to code reviews. Return Optional for maybe one result. Never accept Optional as a parameter. No Optionals in fields. Use map filter flatMap. Throw with orElseThrow at the edge.

Once this becomes habit, fewer crashes make it to staging. And your eyes stop scanning for null checks everywhere.

Why now?

Lambda fever is real after the last round of keynotes. Spring and friends are shipping Java 8 friendly releases. JDK 9 talk is getting louder. This is a good moment to tame null with a small tool we already have.

Cheat sheet: Optional for return types. None for fields. None for parameters. empty for absent. map when you transform. flatMap when your function already returns Optional. orElseGet for expensive defaults. orElseThrow when absence is not okay. Empty collections over Optional of collections.

Takeaway

Optional is a small guardrail. Use it where it speaks clearly. Avoid it where it confuses tools or people. Do that and you get null safety without drama.

General Software Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes